使用AutoFixture实例化对象时,指定属性值

我的测试要求我将不可变Rsvp对象的Response属性(见下文)设置为特定值。

 public class Rsvp { public string Response { get; private set; } public Rsvp(string response) { Response = response; } } 

我最初尝试使用Build().With(x => x.Rsvp, "Attending") ,但意识到这只支持可写属性。

我将其替换为Build().FromFactory(new Rsvp("Attending")) 。 这可行,但对于更复杂的对象来说很麻烦,因为它们与某些属性无关。

例如,如果Rsvp对象具有CreatedDate属性,则此实例化对象的方法将强制我编写Build().FromFactory(new Rsvp("Attending", fixture.Create()))

有没有办法只为不可变对象指定含义属性的值?

AutoFixture最初是作为测试驱动开发(TDD)的工具而构建的,而TDD则是关于反馈的 。 本着GOOS的精神,你应该听听你的测试 。 如果测试难以编写,则应考虑API设计。 AutoFixture倾向于放大这种反馈

坦率地说,不可变类型是C#中的一个Rsvp如果从F#中获取提示并引入复制和更新语义,则可以更容易地使用类似Rsvp的类。 如果您像这样修改Rsvp ,那么整体工作会更容易,因此,作为副产品,也可以用于unit testing:

 public class Rsvp { public string Response { get; private set; } public DateTime CreatedDate { get; private set; } public Rsvp(string response, DateTime createdDate) { Response = response; CreatedDate = createdDate; } public Rsvp WithResponse(string newResponse) { return new Rsvp(newResponse, this.CreatedDate); } public Rsvp WithCreatedDate(DateTime newCreatedDate) { return new Rsvp(this.Response, newCreatedDate); } } 

请注意,我添加了两个WithXyz方法,这些方法返回一个新实例,其中一个值已更改,但所有其他值保持不变。

这将使您能够创建一个Rsvp实例进行测试,如下所示:

 var fixture = new Fixture(); var seed = fixture.Create(); var sut = seed.WithResponse("Attending"); 

或者,作为一个单行:

 var sut = new Fixture().Create().WithResponse("Attending"); 

如果您无法更改Rsvp ,则可以将WithXyz方法添加为扩展方法。

一旦你完成了大约十几次,你就厌倦了它,现在是时候转向F#,其中所有这些(以及更多)是内置的:

 type Rsvp = { Response : string CreatedDate : DateTime } 

您可以使用Rsvp创建一个Rsvp记录,如下所示:

 let fixture = Fixture() let seed = fixture.Create() let sut = { seed with Response = "Attending" } 

或者,作为一个单行:

 let sut = { Fixture().Create() with Response = "Attending" } 

只要Response属性是readonly * ,就可以为Rsvp类型定义自定义SpecimenBuilder

 internal class RsvpBuilder : ISpecimenBuilder { public object Create(object request, ISpecimenContext context) { var pi = request as ParameterInfo; if (pi == null) return new NoSpecimen(); if (pi.ParameterType != typeof(string) || pi.Name != "response") return new NoSpecimen(); return "Attending"; } } 

以下测试通过:

 [Fact] public void ResponseIsCorrect() { var fixture = new Fixture(); fixture.Customizations.Add(new RsvpBuilder()); var sut = fixture.Create(); var actual = sut.Response; Assert.Equal("Attending", actual); } 

*如果由于某种原因, Response属性变为可写,您可以按照此答案中的解决方案。