2015-02-05 76 views
8

Autofixture中是否有一些简单的方法来使用它的构造函数新建对象,但硬编码/指定用于构造函数中单个参数的值?简单的方法来指定单个构造函数参数的值?

我看到,这可以用属性来实现,使用类似:

fixture.Build<MyObj>().With(x=x.Val,"hard coded value").Create()

+0

C#实际上并没有类型安全的语法来引用方法中的单个参数(包括构造函数),所以除非将整个构造函数拉入lambda表达式中,否则这不是真正可行的。这点你不妨直接使用构造函数创建对象,但不使用AutoFixture。你想要这样做的动机是什么?在IME中,通常有一种以不同方式实现大多数相关目标的好方法,但您可能需要以不同的方式来看问题。 – 2015-02-05 17:42:13

+1

希望有一些非类型安全但方便的方式,如Func ,其中输入将作为参数的名称作为字符串。我的一般动机是单元测试。我经常想要新建一个对象,但我只关心一个参数。也许参数值驱动某种计算或变换。我希望价值本身是随机的,但测试需要知道选择了什么样的随机值。鉴于此,单元测试可能会得到一个Property或调用在其操作中使用构造函数参数值的方法。 – SFun28 2015-02-05 17:47:11

+2

[这个答案](http://stackoverflow.com/a/27774580/11635)或[我对这个CodePlex讨论底部的答案]的一些变化](https://autofixture.codeplex.com/discussions/231342)可能会让你开心 – 2015-02-16 09:45:09

回答

10

从讨论这个问题的意见:

我常想新机一个对象,但我只关心一个参数。也许参数值驱动某种计算或变换。我希望价值本身是随机的,但测试需要知道选择了什么样的随机值。

假设这是潜在的问题,我会尝试解决这个问题。

询问对象

最简单的方法是简单地询问对象的值是什么,AutoFixture创建后:

var fixture = new Fixture(); 
var mc = fixture.Create<MyClass>(); 
var specialValue = mc.SpecialValue; 
// Do something with specialValue... 

如果你只需要知道的特殊价值是什么,但你不需要它有一个特定的价值,你可以使用这种技术。

这显然需要您将构造函数参数的值作为(只读)属性公开,但这是a good idea to do anyway

指定创建后的值

如果您需要的参数有一个特定的值,你可以创建后分配给它:

var fixture = new Fixture(); 
var mc = fixture.Create<MyClass>(); 
mc.SpecialValue = "Some really special value"; 

这需要你做出可作为价值可写属性。虽然我个人并不是那么喜欢它,但因为这使对象变得可变,所以很多人已经这样设计它们的对象,如果是这样的话,为什么不利用它呢?

使用复制和更新生成

如果你希望你的对象是不可改变后,您仍然可以使用上述技术的变化。在F#中,您可以使用所谓的copy and update expressions来实现相同的目标。在F#,它会是这样的:

let fixture = Fixture() 
let mc = { 
    fixture.Create<MyRecord>() 
    with SpecialValue = "Some special value!" } 

您可以通过给你的类复制和更新方法在C#中模仿这个,所以你能写出这样的事情:

var fixture = new Fixture(); 
var mc = fixture 
    .Create<MyClass>() 
    .WithSpecialValue("Some really special value"); 

这是我在C#代码中始终使用的技术。 AutoFixture有an idiomatic assertion to test such copy and update methods

注入值参数

如果你可以用特定的构造函数的参数中插入一个固定值活,你可以用AutoFixture内核的基石做到这一点。此测试演示如何:

[Fact] 
public void CustomizeParameter() 
{ 
    var fixture = new Fixture(); 
    fixture.Customizations.Add(
     new FilteringSpecimenBuilder(
      new FixedBuilder("Ploeh"), 
      new ParameterSpecification(
       typeof(string), 
       "specialValue"))); 

    var actual = fixture.Create<MyClass>(); 

    Assert.Equal("Ploeh", actual.SpecialValue); 
} 

然而,这将导致该参数始终是“Ploeh”为fixture实例。它也是重构 - 不安全的,因为它基于引用参数名称的字符串。

+0

嗨马克 - 非常感谢您的详细回复。这些都是很好的解决方法,与您提供的完全相同。共同的主题是,你必须调整你的对象,以便它可以被测试。这对我来说有点代码味道。似乎没有办法在不修改对象的情况下完成我期望的操作。 – SFun28 2015-02-11 14:22:02

+0

它被称为*测试驱动开发*。整个观点是测试提供关于API设计可用性的反馈。 – 2015-02-11 14:55:01

+0

只有当你使用TDD时=)我认为Autofixture是独立于TDD的非常有用的。无论如何,这不是TDD的味道吗?您添加这些属性的唯一原因是由于Autofixture的缺陷。它与TDD的原理无关。 – SFun28 2015-02-11 15:57:17

相关问题