Rhino Mock专家请帮助。
下面的犀牛模拟示例工作正常。
internal class TestClass
{
private ITestInterface testInterface;
public TestClass(ITestInterface testInterface)
{
this.testInterface = testInterface;
}
public bool Method1(int x)
{
testInterface.Method1(x);
return true;
}
}
[TestClass]
public class UnitTest2
{
[TestMethod]
public void TestMethod1()
{
ITestInterface mockProxy = MockRepository.GenerateMock<ITestInterface>();
TestClass tc = new TestClass(mockProxy);
bool result = tc.Method1(5);
Assert.IsTrue(result);
mockProxy.AssertWasCalled(x => x.Method1(5));
}
}
我面临的问题如上所述,我需要在所有子类中创建一个构造函数,如下所示: - 。
internal class testclass1 : TestClass
{
protected testclass1(ITestInterface testInterface) : base(testInterface)
{
}
}
是否有任何解决方法,因为我有大约50个儿童课程?
答案 0 :(得分:4)
正如我对你的问题的评论中提到的,这不是由模拟或单元测试引起的问题。这是使用构造函数注入的自然结果(即提供Dependencies作为构造函数参数)。另一种方法是使用属性注入,即创建一个可写属性,通过它可以设置ITestInterface对象,如下所示:
public class TestClass {
public ITestInterface FooBar {protected get; set; }
}
这样,所有派生类都可以访问FooBar而无需创建自己的构造函数来将ITestInterface传递给基类。
然而,这还有其他后果:构造函数注入通常表示强制依赖。如果没有这种依赖关系,该课程将无效。但是,属性注入通常用于表示可选的依赖项或覆盖默认行为的方法。但是,这种区别并不是一成不变的,如果你真的有几十个来自TestClass构造函数注入的类可能成为维护的真正负担。
如果一个对象需要构造函数参数,那么用户必须传递必需的依赖项。使用属性注入,更容易忘记设置属性以正确设置对象(如果需要依赖项)。此外,使用构造函数注入时,您只需要检查依赖项是否已提供一次(在构造函数中),而使用属性注入时,您更有可能需要在每次使用时检查依赖项的有效性。
同样,如果使用构造函数注入导致维护噩梦,因为你有许多子类,尽管我之前写过,但属性注入仍然是一个可行的选择。 您还可以使用如下的初始化方法表达所需的属性依赖项:
public static class TestClassInitializer{
public T Initialize<T>(this T t, ITestInterface dependency) where T:TestClass{
t.FooBar = dependency;
return t;
}
}
如果你可以强迫自己构建这样的对象:
var tc = new DerivedTestClass().Initialize(mockTestInterface);
您可以在一个点上修改所需的依赖项。如果您现在需要第二个依赖项,只需更新签名以包含第二个依赖项
public static class TestClassInitializer{
public T Initialize<T>(this T t, ITestInterface dependency, IOtherDependency other) where T:TestClass{
t.FooBar = dependency;
t.OtherDependency = other;
return t;
}
}
所有调用Initialize的地方都会在编译时中断。这是一件好事(!),因为您需要来提供所需的依赖项。但是,仅需要更新这些位置,而不是50个派生类以添加其他依赖项。如果你已经使用了构造函数注入,那么你需要更新所有50个类和所有你实例化它们的地方。
另外:如果您知道派生类只有默认构造函数,则可以为所有类创建工厂方法:
public static class TestClassFactory{
public static T Create<T>(ITestInterface dep1, ITestInterface dep2) where T :TestClass, new(){
return new T{FooBar = dep1, OtherDependency = dep2};
}
}
现在可以使用new DerivedTestClass().Initialize(...)
代替TestClassFactory.Create<DerivedTestClass>(mockedDep1, mockedDep2);
。只要TestClassFactory位于同一个程序集中(或者可以通过InternalsVisibleTo访问内部构造函数的程序集中),就可以将实际的构造函数(protected)设置为内部。
如果您使用依赖注入框架/ IoC容器,这一切都不是问题,因为一旦正确设置,它不会忘记提供依赖项。