简体   繁体   中英

NSubstitute using FOrPartsOf to configure void method to do nothing

I have this simple example where I would like to test if a method is being invoked on the same class as the calling method:

    public class MyClass
    {
        public void SomeMethod()
        {
            SomeSubMethod();
        }

        public virtual void SomeSubMethod()
        {
            // do a lot of weird stuff
        }

    }

    public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
            var target = Substitute.ForPartsOf<MyClass>();
            target.Configure().SomeSubMethod(); // <---- please just do nothing

            target.SomeMethod();

            target.Received(1).SomeSubMethod();
        }
    }

My problem is that SomeSubMethod is actually invoked in the unit test, and in my real code I would like to avoid that.

A simple work-a-round is to let SomeSubMethod return something, but now I'm polluting my real code

    public class MyClass
    {
        public void SomeMethod()
        {
            SomeSubMethod();
        }

        public virtual int SomeSubMethod()
        {
            // do a lot of weird stuff
            return 0;
        }

    }

    public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
            var target = Substitute.ForPartsOf<MyClass>();
            target.Configure().SomeSubMethod().Returns(0); // <--- Now the real SomeSubMethod won't be invoked

            target.SomeMethod();

            target.Received(1).SomeSubMethod();
        }
    }

Is there a way to configure a void method to do nothing?

Yours /peter

You can use When..Do syntax to work with void methods:

public void Test1() {
    var target = Substitute.ForPartsOf<MyClass>();
    target.When(x => x.SomeSubMethod()).DoNotCallBase(); // <- do not invoke real code

    target.SomeMethod();

    target.Received(1).SomeSubMethod();
}

Another option, assuming we make SomeMethod virtual , is to substitute for all members using the standard Substitute.For<T> , and opt-in to only call base on the method you want to test.

public void Test2() {
    var target = Substitute.For<MyClass>(); // <- substitute all members
    target.When(x => x.SomeMethod()).CallBase(); // <- except this one, call the real base implementation for SomeMethod 

    target.SomeMethod();
    target.Received(1).SomeSubMethod();

    Assert.Equal(0, target.counter);
}

Documentation links:

According to your description, I rewrite the code:

Public class MyClass
{
    public int x = 0;   // to verify whether the unit test really execute SomeSubMethod()

    public void SomeMethod()
    {
        SomeSubMethod();
    }

    public virtual void SomeSubMethod()
    {
        // do a lot of weird stuff
        int x = 10; 
    }
}

And the test is (please note that I use NUnit framework):

    [TestFixture]
    public class UnitTest1
    {
        [Test]
        public void Test2()
        {
            var myClass = Substitute.For<MyClass>();
            myClass.SomeMethod();
            myClass.Received(1).SomeSubMethod();
            Assert.That(myClass.x, Is.EqualTo(0));
        }
    }

Since the target test method SomeSubMethod() is a virtual method, you don't need to mock part the class MyClass.

Is this what you want?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM