使用AutoFixture作为SutFactory时,定义/管理具有独立值的相同类型的1个构造函数参数

gmn*_*gmn 8 c# tdd autofixture

使用AutoFixture作为SutFactory,我可以看到,如果我注册或冻结某个类型的值,那么该值将用于该类型的所有后续用法.但是,如果我在构造函数中有一个具有两个相同类型的参数的类,例如:

public class ClassA
{
    public double ParameterA { get; private set;}
    public double ParameterB { get; private set;}

    public ClassA(double parameterA, double parameterB)
    {
       ParameterA = parameterA;
       ParameterB = parameterB;
    }

    public void Execute(ClassB object)
    {
        object.Value = (object.Value * ParameterA) /ParameterB;
    }
}
Run Code Online (Sandbox Code Playgroud)

有哪些策略可以使用自动混合为参数A和参数B注入唯一的预定义值,以便测试计算值?

*不幸的是我不能在这里分享我的确切场景,但它使用命令模式操作另一个对象,所以设置parameterA和parameterB维护设计的唯一方法是将它们两者都注入,而构造函数是最好的方法在这种情况下这样做.

Nik*_*nis 5

一种选择是为所有实例定制创建算法ClassA.

var valueA = 1;
var valueB = 2;

var fixture = new Fixture();
fixture.Customize<ClassA>(c => c
    .FromFactory(() => 
        new ClassA(valueA, valueB)));

var result = fixture.Create<ClassA>();
// -> parameterA value is 1
// -> parameterB value is 2
Run Code Online (Sandbox Code Playgroud)

  • 只是好奇...你选择突出"自定义"而不是"注册"的任何理由? (2认同)
  • @grrrrrrrrrrrrr不要担心,我理解你的问题很好(请参阅我在Q上的相关答案的链接) - 我指的是人们可以更简单地将Nikos的答案写成`fixture.Register(()=>新的ClassA(valueA,valueB)`."Customize"更通用,但`Register`在很多情况下都可以成为工作的完美工具.(`Register`的方法体由`fixture.Customize <T>组成(c) => c.FromFactory(creator).OmitAutoProperties());`) (2认同)

Mar*_*ann 5

这是我的观察,大多数时候,当我遇到这样的场景时,我并不特别需要在它们传递给构造函数之前控制它们,而是我需要知道值是什么.

通过向类中添加结构检查属性,可以轻松完成:

public class ClassA
{
    public ClassA(double parameterA, double parameterB)
    {
        this.A = parameterA;
        this.B = parameterB;
    }

    public double A { get; private set }

    public double B { get; private set }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以请求AutoFixture创建一个ClassA实例,而无需进一步调整,然后查询有关值的实例.

  • 如果暂时考虑依赖关系不是基元但接口的情​​况,那么确切的值应该无关紧要; 如果确实如此,该类很可能打破Liskov替代原则.从经验来看,我开始认为同样的原则适用于原始依赖.如果价值很重要,那可能不是一种依赖.也许这些值最好作为方法参数传递?或者事实证明它们最好建模为接口或类?你能分享你的情景吗? (3认同)

gmn*_*gmn 2

在更多地使用这些功能后,我个人发现发生这种情况的对象并不多,因此为该类创建一个简单的自定义可能是最好的选择,例如:

public class ClassACustomization: ICustomization
{
    public double ParameterA { get; set;}
    public double ParameterB { get; set;}

    public void Customize(IFixture fixture)
    {
         //Note: these can be initialized how you like, shown here simply for convenience.
         ParameterA = fixture.Create<double>();
         ParameterB = fixture.Create<double>();
         fixture.Customize<ClassA>(c => c
           .FromFactory(() => 
           new ClassA(ParameterA , ParameterB )));
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现这仍然为我提供了 AutoFixture 的灵活性,而不会影响注入 ParameterA 或 ParameterB 的特定实例的能力(您可以使用构建器方法、构造函数等来设置它们......而不是在自定义中随机值)。