本文介绍了使用AutoFixture实例化[不可变]对象时,指定[只读]属性值[通过ctor args]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My test requires that I set the Response property on an immutable Rsvp object (see below) to a specific value.

public class Rsvp
{
    public string Response { get; private set; }

    public Rsvp(string response)
    {
        Response = response;
    }
}

我最初尝试使用Build<Rsvp>().With(x => x.Rsvp, "Attending")进行此操作,但意识到这仅支持可写属性.

I initially tried to do this using Build<Rsvp>().With(x => x.Rsvp, "Attending"), but realized this only supports writable properties.

我将其替换为Build<Rsvp>().FromFactory(new Rsvp("Attending")).这是可行的,但是对于更复杂的对象来说是麻烦的,这些对象的某些属性无关紧要.

I replaced that with Build<Rsvp>().FromFactory(new Rsvp("Attending")). This works, but is cumbersome for more complex objects where it doesn't matter what some of the properties are.

例如,如果Rsvp对象具有CreatedDate属性,则这种实例化该对象的方法将迫使我编写Build<Rsvp>().FromFactory(new Rsvp("Attending", fixture.Create<DateTime>())).

For instance, if the Rsvp object had a CreatedDate property, this method of instantiating the object would force me to write Build<Rsvp>().FromFactory(new Rsvp("Attending", fixture.Create<DateTime>())).

是否有一种方法只能为不可变对象的含义属性指定值?

Is there a way to only specify values for meaning properties for an immutable object?

推荐答案

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

AutoFixture was originally build as a tool for Test-Driven Development (TDD), and TDD is all about feedback. In the spirit of GOOS, you should listen to your tests. If the tests are hard to write, you should consider your API design. AutoFixture tends to amplify that sort of feedback.

坦率地说,不可变类型是C#的难题,但是如果您从F#中引入线索并引入 copy和update 语义,则可以更轻松地使用Rsvp之类的类.如果您这样修改Rsvp,则整体上将更容易使用,因此,作为副产品,也可以进行单元测试:

Frankly, immutable types are a pain in C#, but you can make it easier to work with a class like Rsvp if you take a cue from F# and introduce copy and update semantics. If you modify Rsvp like this, it's going to be much easier to work with overall, and thus, as a by-product, also to unit test:

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方法,它们返回一个新实例,其中一个值已更改,但所有其他值保持不变.

Notice that I've add two WithXyz methods, that return a new instance with that one value changed, but all other values held constant.

这将使您能够创建Rsvp的实例以进行如下测试:

This would enable you to create an instance of Rsvp for testing purposed like this:

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

或者,单线:

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

如果不能更改Rsvp,则可以添加WithXyz方法作为扩展方法.

If you can't change Rsvp, you can add the WithXyz methods as extension methods.

完成此操作大约十二次后,您会感到厌倦,现在是时候迁移到F#了,所有这些(以及更多)都已内置在其中:

Once you've done this about a dozen times, you get tired of it, and it's time to make the move to F#, where all that (and more) is built-in:

type Rsvp = {
    Response : string
    CreatedDate : DateTime }

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

You can create an Rsvp record with AutoFixture like this:

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

或者,单线:

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

这篇关于使用AutoFixture实例化[不可变]对象时,指定[只读]属性值[通过ctor args]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-25 07:42