【问题标题】:NSubstitute use real instance of a class as substitute, except one methodNSubstitute 使用类的真实实例作为替代,除了一个方法
【发布时间】:2018-04-17 16:04:48
【问题描述】:

除了少数方法外,NSubstitute 中是否有任何内置方法可以用其实例模拟一个类?

在示例中,我想保留实例的全部功能,但检查是否使用特定参数调用方法。

其实我就是这么做的

public class Wrapper: IInterface
{
    public IInterface real;
    public IInterface sub;

    public void Wrapper(IIterface realInstance, IIterface nsubstitute)
    {
        real = realInstance;
        sub = nsubstitute;
    }

    public void MethodThatShouldWorkAsAlways()
    {
        real.MethodThatShouldWorkAsAlways();
    }

    public intMethodToBeTested(int a)
    {
        return sub.MethodToBeTested();
    }
}

这样做的原因是我正在测试足够复杂的东西,以至于我不能简单地手动创建包装器,这既费时又容易出错。如果 Nsubstitute 允许这样的东西会很好:

IIterface realMock = NSubstitute.Mock< IIterface>( new RealClass());

realMock.MethodThatShouldWorkAsAlways(); // regular logic
realMock.MethodToBeTested(4).Returns( 3); // overrides the method to always returns 3

但到目前为止我没有找到任何文档。

【问题讨论】:

  • 模拟未密封的实际类。被覆盖的成员必须是虚拟的才能正常工作。
  • 特别注意与使用部分模拟/订阅相关的警告。
  • 测试实际实现有什么问题?
  • 实现已测试,我需要测试使用它的类并验证最终调用了一个方法

标签: c# unit-testing mocking nsubstitute


【解决方案1】:

如果我正确理解了您的情况,那么您有一个正在测试的类,它将 IIterface 作为依赖项,并且您希望确保您正在测试的类正在调用 MethodToBeTested(int) 方法。

这可以使用生成模拟的.ForPartsOf&lt;T&gt;() 方法来完成。这会生成一个“部分模拟”,除非您提供覆盖,否则它将调用底层类实现。不过,它有一个很大的要求:您要覆盖(或确保被调用)的方法必须是 virtual(如果在基类中定义,则为 abstract)。

一旦你有了模拟,你就可以使用.Received()断言模拟上的方法被调用(或者没有被调用,如果你使用.DidNotReceive())。

如果您希望使用基本实现,则实际上不需要覆盖 MethodToBeTested(int) 的行为。

这是一个具体示例,基于您的示例代码:

对于依赖项,您有一个实现接口IIterfaceRealClass,并且您希望确保调用了MethodToBeTested(int)。所以这些可能看起来像这样:

public interface IIterface
{
    void MethodThatShouldWorkAsAlways();
    int MethodToBeTested(int a);
}

public class RealClass: IIterface
{
    public void MethodThatShouldWorkAsAlways()
    { }

    public virtual int MethodToBeTested(int a)
    { return a; }
}

然后你就有了你实际测试的类,它使用 IIterface 作为依赖:

public class ClassThatUsesMockedClass
{
    private readonly IIterface _other;

    public ClassThatUsesMockedClass(IIterface other)
    {
        _other = other;
    }

    public void DoSomeStuff()
    {
        _other.MethodThatShouldWorkAsAlways();

        _other.MethodToBeTested(5);
    }
}

现在,您要测试 DoSomeStuff() 是否实际调用了 MethodToBeTested(),因此您需要创建 SomeClass 的部分模拟,然后使用 .Received() 来验证它是否被调用:

    [Test]
    public void TestThatDoSomeStuffCallsMethodToBeTested()
    {
        //Create your mock and class being tested
        IIterface realMock = Substitute.ForPartsOf<RealClass>();
        var classBeingTested = new ClassThatUsesMockedClass(realMock);

        //Call the method you're testing
        classBeingTested.DoSomeStuff();

        //Assert that MethodToBeTested was actually called
        realMock.Received().MethodToBeTested(Arg.Any<int>());

    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-10
    • 1970-01-01
    • 2018-11-11
    • 1970-01-01
    • 2014-11-05
    相关资源
    最近更新 更多