Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moq and file/data saving in C#

Ok, I am working on some unit testing, and my understanding is (based on "The Art of Unit Testing" by Roy Osherove) that if you're hitting a DB or actually saving a file, you're integration testing, not unit testing.

Given that, I have the following (yes, I know this violates SRP, but it illustrates my point):

public class PrimeChecker : IPrimeChecker
{
    public bool IsPrime(int num)
    {
        if (num < 2)
        {
            return false;
        }

        if (num > 2 && num % 2 == 0)
        {
            return false;
        }

        if (num % 2 != 0)
        {
            for (int i = 3; (i * i) <= num; i += 2)
            {
                if (num % i == 0)
                {
                    return false;
                }
            }
        }

        return true;
    }

    public bool Save()
    {
        return true;
    }
}

Note the the Save() method is simply a stub right now.

I'm trying to use Moq to simulate saving. So my test looks like this:

[Test]
    public void Save_WhenCalled_ExecutesSave()
    {
        var mock = new Mock<IPrimeChecker>();

        mock.Setup(x => x.Save());

        IPrimeChecker checker = mock.Object;
        checker.Save();

        mock.Verify(x => x.Save(), Times.Once);
    }

So if I had a fully-functioning Save() method in my class, is this the correct way to mock functionality? Because as I previously stated, my understanding is that for unit tests, I'm not supposed to actually write a file/save to a DB.

If this isn't correct, what should I be doing?

like image 348
MJR Avatar asked Jan 12 '18 14:01

MJR


People also ask

What is the use of MOQ library?

What is MOQ? MOQ is a mocking library made for your Unit Tests. MOQ is intended to be simple to use, strongly typed (no magic strings, and therefore full compiler-verified and refactoring-friendly) and minimalistic (while still fully functional).

How do I use MoQ in unit testing?

To install the Moq framework to your test project, you can easily add it as a NuGet package: The other option is to select your unit test project and manage NuGet packages through UI. It is easy to set up a system under test – Moq makes testing easier because it generates appropriate mocks/stubs for you.

Does Moq work on my Machine?

It’s a great way to combat the common “works on my machine” problem. Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation. Moq is a mock object framework for .NET that greatly simplifies the creation of mock objects for unit testing.

Is it possible to mock a class in Moq?

While mocking a class is not recommended, it is possible to do so. To make a class mockable, it needs to be a public class, and the method you want to mock has to be virtual. Can you use Moq with MSTest? Yes, you can use Moq with MSTest. Moq should support every popular unit testing framework, including xUnit, NUnit, and MSTest.


1 Answers

Assume your checker has a dependency on something needed to save.

Lets say

public interface IPrimeDb {
    bool Save(int prime);
}

And the checker looked like this

public class PrimeChecker {
    private IPrimeDb primeDb;

    public PrimeChecker(IPrimeDb db) {
        this.primeDb = db;
    }

    public bool IsPrime(int num) {
        if (num < 2) {
            return false;
        }

        if (num > 2 && num % 2 == 0) {
            return false;
        }

        if (num % 2 != 0) {
            for (int i = 3; (i * i) <= num; i += 2) {
                if (num % i == 0) {
                    return false;
                }
            }
        }

        return true;
    }

    public bool Save(int prime) {
        if (IsPrime(prime))
            return primeDb.Save(prime);

        return false;
    }
}

A test to test that the save is being called when a valid prime is provided can look like this.

[TestMethod]
public void Save_WhenCalled_ExecutesSave() {
    //Arrange
    var num = 3;
    var mock = new Mock<IPrimeDb>();

    var sut = new PrimeChecker(mock.Object);

    mock.Setup(_ => _.Save(num)).Returns(sut.IsPrime(num));

    //Act
    var actual = sut.Save(num);

    //Assert
    Assert.IsTrue(actual);
    mock.Verify(_ => _.Save(num), Times.AtMostOnce());
}

When unit testing you tend to mock the dependencies of the subject under test so as to avoid undesirable behavior. This allows the test to be exercised in isolation.

like image 139
Nkosi Avatar answered Oct 26 '22 23:10

Nkosi