使用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
属性变为可写,您可以按照此答案中的解决方案。