How write stub method with NUnit in C#

15,465

Solution 1

A good way to allow you to write stubs is to use dependency injection. FirstDeep depends on SecondDeep and in your test you want to replace SecondDeep with a stub.

First change your existing code by extracting an interface for SecondDeep and then inject that into FirstDeep in the constructor:

interface ISecondDeep {

  Boolean SomethingToDo(String str);

}

class SecondDeep : ISecondDeep { ... }

class FirstDeep {

  readonly ISecondDeep secondDeep;

  public FirstDeep(ISecondDeep secondDeep) {
    this.secondDeep = secondDeep;
  }

  public String AddA(String str) {   
    var flag = this.secondDeep.SomethingToDo(str);
    ...
  }

}

Note that FirstDeep no longer creates a SecondDeep instance. Instead an instance is injected in the constructor.

In your test you can create a stub for ISecondDeep where SomethingToDo always returns true:

class SecondDeepStub : ISecondDeep {

  public Boolean SomethingToDo(String str) {
    return true;
  }

}

In the test you use the stub:

var firstDeep = new FirstDeep(new SecondDeepStub());

In production code you use the "real" SecondDeep:

var firstDeep = new FirstDeep(new SecondDeep());

Using a dependency injection container and a stubbing framework can make a lot of this easier to do.

If you don't want to rewrite your code you can use a framework for intercepting calls like Microsoft Moles. In the next version of Visual Studio a similar technology will be available in the Fakes Framework.

Solution 2

To make your code testable, do not instantiate dependencies inside your class. Use dependency injection (via constructor, property or parameter). Also use abstract classes or interfaces to allow mocking of dependencies:

class FirstDeep
{
    private ISecondDeep oa;

    public FirstDeep(ISecondDeep oa) 
    { 
        this.oa = oa;
    }

    public string AddA(string str)
    {
       return String.Concat(str, oa.SomethingToDo(str) ? "AAA" : "BBB");
    }
}

Depending on abstractions allows you to test your class in isolation.

interface ISecondDeep
{
   bool SomethingToDo(string str);
}

class SecondDeep : ISecondDeep
{
    public bool SomethingToDo(string str)
    {
       bool flag = false;
       if (str.Length < 10)
       {
           // without abstraction your test will require database
       }
       return flag;
    }
}

Here is test sample (using Moq). It shows you how you can return true from call to your mocked dependency:

[TestFixture]
class Tests
{
    [Test]
    public void AddAAATest()
    {
        // Arrange
        Mock<ISecondDeep> secondDeep = new Mock<ISecondDeep>();
        secondDeep.Setup(x => x.SomethingToDo(It.IsAny<string>())).Returns(true);
        // Act
        FirstDeep fd = new FirstDeep(secondDeep.Object);
        // Assert
        Assert.That(fd.AddA("ABD"), Is.EqualTo("ABCAAA"));
     }
}
Share:
15,465

Related videos on Youtube

Smit
Author by

Smit

null

Updated on June 04, 2022

Comments

  • Smit
    Smit almost 2 years

    I have 2 classes:

    • FirstDeep.cs
    • SecondDeep.cs

      I did simple code for example:

    
    class FirstDeep
        {
            public FirstDeep() { }
    
            public string AddA(string str)
            {
                SecondDeep sd = new SecondDeep();
                bool flag = sd.SomethingToDo(str);
    
                if (flag == true)
                    str = string.Concat(str, "AAA");
                else
                    str = string.Concat(str, "BBB");
    
                return str;
            }
        }
    
    

    and

    class SecondDeep
        {
            public bool SomethingToDo(string str)
            {
                bool flag = false;
                if (str.Length < 10)
                {
                    //todo something in DB, and after that flag should be TRUE
                }
                return flag;
            }
        }
    

    Then I want to write unit test for method "AddA":

    class Tests
        {
            [Test]
            public void AddATest()
            {
                string expected = "ABCAAA";
    
                FirstDeep fd = new FirstDeep();
                string res = fd.AddA("ABC");
    
                Assert.AreEqual(expected, res);
            }
        }
    

    And after that I have trouble, I don't know how correct write stub for method SomethingToDo in my Test class. I always have false. I should just return TRUE. But how?