15

我有一个用“NSubstitute”模拟的接口,它包含返回 concreate 类的属性,即返回值不是接口。例如

public interface ISomething
{
    SomeObj First { get; }
    SomeObj Second { get; }
}

“SomeObj”具体类有一个默认构造函数,但“NSubstitute”总是为这些属性返回“null”。类本身不在我的控制之下,所以我不能简单地让它从接口派生。

'NSubstitute' 可以模拟这些类型的属性吗?或者有没有办法覆盖行为?否则我必须在测试之前手动初始化模拟,这可能是很多代码(即使它通过通用方法重用)。

也许我忽略了一个更简单的解决方案?

4

2 回答 2

8

如果类具有默认(无参数)构造函数并且其所有成员都是虚拟的,则类将被自动模拟(请参阅Auto 和递归模拟简介中的注释)。这样做的目的是减少潜在的不必要的(破坏性?)副作用,如果我们使用替代品并突然命中非虚拟的、未模拟的代码路径,该路径在我们认为是假的实例中做坏事。

NSubstitute 没有办法覆盖这种行为。相反,我建议通过您自己的工厂方法(例如Sub.For<T>(...)测试项目中的静态方法)创建所有替代品,该方法使用 NSubstitute 生成替代品,然后应用您需要的所有特定初始化规则,例如使用反射来存根值对于每个类属性。

希望这可以帮助。

可能的相关链接:

于 2013-06-19T05:59:17.997 回答
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在你的测试中模拟。

于 2014-05-15T21:01:00.000 回答