我正在尝试使用SUT Factory'pattern'来创建我的SUT。
鉴于SUT结构:
namespace MySut
{
public class Dep1
{
}
public class Dep2
{
}
public class Sut
{
public Sut( Dep1 dep1, Dep2 dep2 )
{
}
}
}
我正在使用AutoFixture,我想知道什么是折叠以下规格和相关SUT工厂方法[有价值但是]繁忙工作的最佳方法:
namespace MySpecifications
{
using MySut;
public class MySpecification
{
public void TestCore()
{
// Dont care about dependencies, testing core functionality
var sut = CreateSut();
}
public void TestDep1Interaction()
{
// Dont care about Dep2, want to observe stuff on the Dep1 dependent object
var sut = CreateSut( new Mock<Dep1>().Object );
}
public void TestDep2Interaction()
{
// Dont care about Dep1, want to observe stuff on the Dep2 dependent object
var sut = CreateSut( new Mock<Dep2>().Object );
}
private object CreateSut( )
{
return CreateSut( CreateDep1(), CreateDep2() );
}
private object CreateSut( Dep1 dep1 )
{
return CreateSut( dep1, CreateDep2() );
}
private object CreateSut( Dep2 dep2 )
{
return CreateSut( CreateDep1(), dep2 );
}
private Sut CreateSut( Dep1 dep1, Dep2 dep2 )
{
return new Sut( dep1, dep2 );
}
private static Dep1 CreateDep1()
{
return new Fixture().CreateAnonymous<Dep1>();
}
private static Dep2 CreateDep2()
{
return new Fixture().CreateAnonymous<Dep2>();
}
}
}
类似于:
public class MyAutoFixturedSpecification
{
public void TestCore()
{
// Dont care about dependencies, testing core functionality
var sut = CreateSut();
}
public void TestDep1Interaction()
{
// Dont care about Dep2, want to observe stuff on the Dep1 dependent object
var sut = CreateSut( new Mock<Dep1>().Object );
}
public void TestDep2Interaction()
{
// Dont care about Dep1, want to observe stuff on the Dep2 dependent object
var sut = CreateSut( new Mock<Dep2>().Object );
}
private object CreateSut( params object[] injectedNonAnonymouses )
{
return new Fixture( ).Build<Sut>( )./*??????*/;
}
}
或:
public class MyAnticipatedAutoFixturedSpecification
{
public void TestCore()
{
// Dont care about dependencies, testing core functionality
var sut = new Fixture( ).Build<Sut>().CreateAnonymous( );
}
public void TestDep1Interaction()
{
// Dont care about Dep2, want to observe stuff on the Dep1 dependent object
var sut = new Fixture().Build<Sut>()/*.With( new Mock<Dep1>().Object )*/.CreateAnonymous();
}
public void TestDep2Interaction()
{
// Dont care about Dep1, want to observe stuff on the Dep2 dependent object
var sut = new Fixture().Build<Sut>()/*.With( new Mock<Dep2>().Object )*/.CreateAnonymous();
}
}
即删除所有工厂垃圾,以便我的规格可以轻松应对过渡到:
namespace MySutWithNewDependency
{
public class Dep1
{
}
public class Dep2
{
}
public class Dep3
{
}
public class Sut
{
public Sut( Dep1 dep1, Dep2 dep2, Dep3 dep3 )
{
}
}
}
虽然与自动锁定容器的概念有重叠,但我仍然没有寻找金锤 - 只是一种方法可以一次模拟0或1个东西,但能够自定义依赖的创建对象无需在其“依赖集”发生变化时重新访问对Sut构造函数的显式调用。
(也使用xUnit.net(SubSpec样式),Moq,Ninject2(虽然不想在我的规范中使用DI))
答案 0 :(得分:4)
AutoFixture可以或多或少地为您完成所有这些,而无需额外的脚手架。我从一个基本的Fixture开始,用它来解决Sut
:
var fixture = new Fixture();
var sut = fixture.CreateAnonymous<Sut>();
这假设AutoFixture可以自动创建Dep1
和Dep2
,但是如上所述,它们可以因为它们具有默认构造函数。
如果要覆盖特定类型,可以使用Register方法,如下所示:
var fixture = new Fixture();
var mock = new Mock<Dep1>();
fixture.Register(mock.Object);
// Setup mock if necessary...
var sut = fixture.CreateAnonymous<Sut>();
这将导致fixture
在需要mock.Object
的任何时候使用Dep1
,包括调用Sut
构造函数时。这绝对符合您在不断发展的构造函数中保持健壮的要求,也是AutoFixture像这样构建的主要原因之一。
在更现实的场景中,Dep1和Dep2可能是接口,在这种情况下,您可能希望将它们注册为“默认夹具”的一部分。这当然也可能是因为最后一次调用Register wins 。这意味着您可以使用一些良好的默认值配置Fixture实例,并且仍然可以在需要时覆盖特定类型。
我个人使用AutoFixture作为自动模拟容器。 This discussion提供了使用AutoFixture 1.1 API如何实现这一点的提示,但AutoFixture 2.0的新内核将提供更好的可扩展性选项。当我到达它时,我会写一篇关于这个主题的博客文章。
P.S。对于迟到的回复感到抱歉,但我之前没有看到你的问题。将来,请随时给我打电话(例如在Twitter上)以获得更快的回复。