我有一个我正在使用'NSubstitute'进行模拟的接口,它包含返回concreate类的属性,即返回值不是接口。 e.g
public interface ISomething
{
SomeObj First { get; }
SomeObj Second { get; }
}
'SomeObj'具体类有一个默认构造函数,但'NSubstitute'总是为这些属性返回'null'。这个类本身不在我的控制之下,所以我不能简单地从接口派生出它。
可以'NSubstitute'嘲笑这些类型的属性吗?或者有没有办法覆盖行为?否则我必须在测试之前手动初始化模拟,这可能是很多代码(即使它通过常用方法重用)。
也许有一个更简单的解决方案,我已经过度了?
答案 0 :(得分:7)
如果类具有默认(无参数)构造函数并且其所有成员都是虚拟的,则将自动模拟类(请参阅Auto and recursive mocks简介中的注释)。这样做的目的是为了减少不必要的(破坏性的)副作用的可能性,如果我们使用替代品并且突然遇到一个非虚拟的,未被嘲弄的代码路径,在我们认为是假的实例中做坏事。
NSubstitute没有办法覆盖此行为。相反,我建议您通过自己的工厂方法(例如测试项目中的静态Sub.For<T>(...)
方法)创建所有替代品,使用NSubstitute生成替代品,然后应用您需要的所有特定初始化规则,比如使用反射来存根每个类属性的值。
希望这有帮助。
答案 1 :(得分:0)
它不算作自动模拟,但你也问过“或者有没有办法覆盖行为?”并且“也许有一个更简单的解决方案,我已经过度了?”
这个答案依赖于你问题中的陈述:
SomeObj
是一个超出您控制范围的类,我认为它是单独测试的,或者是不可测试的SomeObj
有一个默认构造函数当然,它要求你“在测试之前手动初始化模拟”,但由于你没有告诉我们这个对象是什么,所以不可能知道完全实现需要做多少工作。
public class SomeObj
{
// Non-virtual to prevent auto-mocking
public void Dummy() { }
}
public interface ISomething
{
SomeObj First { get; }
SomeObj Second { get; }
}
[TestMethod]
public void Test_17182355ms()
{
ISomething mockedSomething = Substitute.For<ISomething>();
SomeObj firstObj = mockedSomething.First;
Assert.IsNull(firstObj);
mockedSomething.First.Returns(new SomeObj());
mockedSomething.Second.Returns(new SomeObj());
firstObj = mockedSomething.First;
Assert.IsNotNull(firstObj);
}
另一种方法虽然并非没有自身的缺点,但却是为SomeObj
提取自己的界面,如下所示:
public interface ISomeObj
{
void Dummy();
}
public class MySomeObj : SomeObj, ISomeObj
{
}
然后在测试中模拟ISomeObj
。