除了一种方法之外,NSubstitute使用类的实例作为替换

时间:2018-04-17 16:04:49

标签: c# unit-testing mocking nsubstitute

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

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

1 个答案:

答案 0 :(得分:1)

如果我正确理解你的情况,你有一个正在测试的类,它将IIterface作为一个依赖项,你想确保你的类调用MethodToBeTested(int)方法'重新测试。

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

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

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

以下是基于示例代码的具体示例:

对于依赖项,您有RealClass实现接口IIterface,并且您希望确保调用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>());

    }