C# IList<;某物>;构造函数参数与自动夹具

C# IList<;某物>;构造函数参数与自动夹具,c#,unit-testing,autofixture,C#,Unit Testing,Autofixture,使用,我试图构造项目的匿名实例: _f=new Fixture().Customize(new AutoMoqCustomization()); _p=_f.CreateAnonymous<Project>(); 堆栈跟踪没有意义(至少对我来说)。只是一些思考,雅达雅达: 失败:System.Reflection.TargetInvocationException:调用的目标已引发异常。 ----System.ArgumentException:值不在预期范围内。 在Syste

使用,我试图构造
项目的匿名实例

 _f=new Fixture().Customize(new AutoMoqCustomization());
 _p=_f.CreateAnonymous<Project>();
堆栈跟踪没有意义(至少对我来说)。只是一些思考,雅达雅达:

失败:System.Reflection.TargetInvocationException:调用的目标已引发异常。
----System.ArgumentException:值不在预期范围内。
在System.RuntimeMethodHandle.\u InvokeConstructor(IRuntimeMethodInfo方法,对象[]参数,SignatureStruct&signature,RuntimeType declaringType)

那么-如何确保autoFixture在匿名的合作伙伴集合中通过,以便构建它


这不是IList的故障。还有另一个参数叫做
优先级
<代码>优先级本身保持
度量
度量
保持
IList
并在构造函数中调用
防范空(指示器)

看起来是这样的:

fixture.CreateAnonymous<Foo>(); //kaboom!
public class Foo{
  public Foo(IList<Bar> bars){
    Guard.AgainstEmpty(bars); //just checks count for ienumerable & throws if 0
    Bars=bars;
  }
  public IList<Bar> Bars {get;private set;} //should be readonly collection...
}

public class Fizz{
  public Fizz(Foo foo){
    Foo=foo;
  }
  public Foo{get;private set;}
}

public class Bar{}
fixture.CreateAnonymous()//卡布姆!
公开课Foo{
公共食品(IList酒吧){
Guard.AgainstEmpty(条);//只检查ienumerable的计数,如果为0则抛出
钢筋=钢筋;
}
公共IList条{get;private set;}//应为只读集合。。。
}
公开课的嘶嘶声{
公共汽水(富富){
Foo=Foo;
}
公共Foo{get;私有集;}
}
公共类Bar{}
Guard.AgainstEmpty
方法中构造失败。所以-问题变成了-如何确保AutoFixture在构建foos之前填充bars集合中的一些条?

这很有帮助。浏览通常会有所帮助

var indicators=_f.CreateMany<Indicator>();
_f.Register<IList<Indicator>>(()=>indicators.ToList());
var指标=_f.CreateMany();
_f、 寄存器(()=>indicators.ToList());
也许还有更好的办法


总的来说,目前情况是这样的:

  _f=new Fixture().Customize(new AutoMoqCustomization());
  var indicators=_f.CreateMany<Indicator>();
  _f.Register<IList<Indicator>>(()=>indicators.ToList());
  var regionName=_f.CreateAnonymous<string>();
  _f.Register<string,Country,bool,Region>((name,country,call)=>
    new Region(regionName,_f.CreateAnonymous<Country>(),true));
  _c.Set(x=>x.Regions,_f.CreateMany<Region>().ToList());
  _f.Register<IList<ManagementBoardEntry>>(()=>
    _f.CreateMany<ManagementBoardEntry>().ToList());
  _f.Register<IList<FinancialInfoEntry>>(()=>
    _f.CreateMany<FinancialInfoEntry>().ToList());
  _f.Register<IList<Partner>>(()=>_f.CreateMany<Partner>().ToList());
  _p=_f.CreateAnonymous<Project>();
\u f=新夹具()。自定义(新的AutoMoqCustomization());
var indicators=_f.CreateMany();
_f、 寄存器(()=>indicators.ToList());
var regionName=_f.CreateAnonymous();
_f、 注册((姓名、国家、电话)=>
新区域(regionName,_f.CreateAnonymous(),true));
_c、 Set(x=>x.Regions,_f.CreateMany().ToList());
_f、 寄存器(()=>
_f、 CreateMany().ToList());
_f、 寄存器(()=>
_f、 CreateMany().ToList());
_f、 寄存器(()=>_f.CreateMany().ToList());
_p=_f.CreateAnonymous();
不能称之为美丽(欢迎任何重构建议),但它仍然比手动编写所有内容要好得多


使用IList肯定会有错误的选择。更糟糕的是,我还在属性中使用
IList
。这会邀请客户机直接使用它们,而不是通过聚合根

使用
params
时有一个缺点。不能使用多个(除非我又错过了一些基础知识)。我收到的列表作为输入(excel工作表DOM的一部分),不知道编译时会有多少元素

模型真的很新鲜。刚烤好(所以我很有可能对这些空白检查错了,我会和客户和业务分析师讨论这个问题)

我的策略是自由地雕刻它,并通过单元测试将它推向期望的状态。这就是我有点不喜欢严格TDD的实际原因。它抢走了焦点,迫使我过早地考虑细节而不是整个画面。我更喜欢把它画出来并加以改进,直到它看起来很好。但那可能是因为我考试不够流利


无论如何,谢谢你给我的好建议。我将继续学习有关AutoFixture的更多信息。

我无法像这里所描述的那样再现此问题。AutoMoqCustomization应该创建一个模拟的
IList
,因为这是一个接口。但是,我怀疑Guard.AgainstEmpty方法中正在发生某些事情,该方法试图以“非法”的方式使用Mock。您能从堆栈跟踪中看到在您自己的代码中引发异常的位置,并共享该代码吗?@markseemann ahhh。。。。看起来不是它看起来的样子。稍后将为我的问题添加详细信息。+1映射到CreateMany目前是填充列表的惯用方法,尽管您可以在如下语句中完成:
\u f.Register(()=>\u f.CreateMany().ToList())@Mark我说过你的工具救了我吗?这个项目类拥有大量的价值对象,只有上帝知道它们有多深。仅仅设置一个有效的项目就需要几个小时。但总体考虑:AutoFixture是基于一组使事情变得简单的约定。当定制AutoFixture变得困难时,您应该重新考虑您的设计。在这种情况下,例如,考虑“非空”前提是否真的有意义。通常,当我们使用列表时,预期它们可以有任何长度,包括0,因此违反了POLA。但是,如果您真的必须在列表中至少有一个实例,那么考虑一个这样的替代构造函数:<代码>公共项目(伙伴伙伴,PARAMPartners []Partners)。
这强制API的所有使用者(包括AutoFixture)至少提供一个合作伙伴。这有助于AutoFixture正确连接所有内容,但也有助于所有其他开发人员(包括您未来的自己)正确使用您的API:)关于使用params数组的另一个注释:您正确的是,每个ctor只能有一个params数组,但是如果你觉得需要更多的话,那意味着什么:它是否有SRP违规的味道?可能是:)
  _f=new Fixture().Customize(new AutoMoqCustomization());
  var indicators=_f.CreateMany<Indicator>();
  _f.Register<IList<Indicator>>(()=>indicators.ToList());
  var regionName=_f.CreateAnonymous<string>();
  _f.Register<string,Country,bool,Region>((name,country,call)=>
    new Region(regionName,_f.CreateAnonymous<Country>(),true));
  _c.Set(x=>x.Regions,_f.CreateMany<Region>().ToList());
  _f.Register<IList<ManagementBoardEntry>>(()=>
    _f.CreateMany<ManagementBoardEntry>().ToList());
  _f.Register<IList<FinancialInfoEntry>>(()=>
    _f.CreateMany<FinancialInfoEntry>().ToList());
  _f.Register<IList<Partner>>(()=>_f.CreateMany<Partner>().ToList());
  _p=_f.CreateAnonymous<Project>();