Sam
Sam

Reputation: 15761

When to use a Mocking Framework?

So I am playing around with mocking frameworks (Moq) for my unit tests, and was wondering when you should use a mocking framework?

What is the benefit/disadvantage between the following two tests:

public class Tests
{
    [Fact]
    public void TestWithMock()
    {
        // Arrange
        var repo = new Mock<IRepository>();

        var p = new Mock<Person>();
        p.Setup(x => x.Id).Returns(1);
        p.Setup(x => x.Name).Returns("Joe Blow");
        p.Setup(x => x.AkaNames).Returns(new List<string> { "Joey", "Mugs" });
        p.Setup(x => x.AkaNames.Remove(It.IsAny<string>()));

        // Act
        var service = new Service(repo.Object);
        service.RemoveAkaName(p.Object, "Mugs");

        // Assert
        p.Verify(x => x.AkaNames.Remove("Mugs"), Times.Once());
    }

    [Fact]
    public void TestWithoutMock()
    {
        // Arrange
        var repo = new Mock<IRepository>();

        var p = new Person { Id = 1, Name = "Joe Blow", AkaNames = new List<string> { "Joey", "Mugs" } };

        // Act
        var service = new Service(repo.Object);
        service.RemoveAkaName(p, "Mugs");

        // Assert
        Assert.True(p.AkaNames.Count == 1);
        Assert.True(p.AkaNames[0] == "Joey");
    }
}

Upvotes: 7

Views: 11896

Answers (7)

Mike Nakis
Mike Nakis

Reputation: 61969

When should you use mocks? Almost never.

Mocks turn your tests into white-box tests, which are very labor intensive to write and extremely labor intensive to maintain. This may not be an issue if you are in the medical industry, aerospace industry, or other high-criticality software business, but if you are writing regular commercial grade software, your tests should be black-box tests. In other words, you should be testing against the interface, not against the implementation.

What to use instead of mocks?

Use fakes. Martin Fowler has an article explaining the difference here: https://martinfowler.com/bliki/TestDouble.html but to give you an example, an in-memory database can be used as fake in place of a full-blown RDBMS. (Note how fakes are a lot less fake than mocks.)

Upvotes: 0

Ilya Palkin
Ilya Palkin

Reputation: 15737

There are some rules I use writing unit-tests.

  1. If my System Under Test (SUT) or Object Under Test has dependencies then I mock them all.
  2. If I test a method that returns result then I check result only. If dependencies are passed as parameters of the method they should be mocked. (see 1)
  3. If I test 'void' method then verifying mocks is the best option for testing.

There is an old one article by Martin Fowler Mocks Aren't Stubs.

In first test you use Mock and in the second one you use Stub.

Also I see some design issues that lead to your question.

If it is allowed to remove AkaName from AkaNames collection then it is OK to use stub and check state of the person. If you add specific method void RemoveAkaName(string name) into Person class then mocks should be used in order to verify its invocation. And logic of RemoveAkaName should be tested as part of Person class testing.

I would use stub for product and mock for repository for you code.

Upvotes: 2

TGH
TGH

Reputation: 39248

A mocking framework is useful for simulating the integration points in the code under test. I would argue that your concrete example is not a good candidate for a mocking framework as you can already inject the dependency (Person) directly into the code. Using a mocking framework actually complicates it in this case.

A much better use case is if you have a repository making a call to a database. It is desirable from a unit test perspective to mock the db call and return predetermined data instead. The key advantages of this is removing dependencies on exiting data, but also performance since the db call will slow the test down.

Upvotes: 1

Vidya
Vidya

Reputation: 30300

Use mock objects to truly create a unit test--a test where all dependencies are assumed to function correctly and all you want to know is if the SUT (system under test--a fancy way of saying the class you're testing) works.

The mock objects help to "guarantee" your dependencies function correctly because you create mock versions of those dependencies that produce results you configure. The question then becomes if the one class you're testing behaves as it should when everything else is "working."

Mock objects are particularly critical when you are testing an object with a slow dependency--like a database or a web service. If you were to really hit the database or make the real web service call, your test will take a lot more time to run. That's tolerable when it's only a few extra seconds, but when you have hundreds of tests running in a continuous integration server, that adds up really fast and cripples your automation.

This is what really makes mock objects important--reducing the build-test-deploy cycle time. Making sure your tests run fast is critical to efficient software development.

Upvotes: 11

Dalton
Dalton

Reputation: 1354

Mock is used to test object that cannot function in isolation. suppose function A is dependent on function B, to perform unit testing on function A we even end up testing function B.By using mock you can simulate the functionality of function B and testing can be focussed only on function A.

Upvotes: 1

dariusc
dariusc

Reputation: 1089

Mocking has many benefits especially in agile programming where many quick release cycles means that sytem strucutre and real data might be incomplete. In such cases you can mock a repository to mimic production code in order to continue work on ui, or services. This is usually complemented with an IoC mechanism like Ninject to simplify the switch to the real repositories. The two examples you give are equal and without any other context I would say it's a matter of choice between them. The fluent api in moq might be easier to read as its kind of self documenting. That's my opinion though ;)

Upvotes: 1

peanut
peanut

Reputation: 1482

The mocking framework is used to remove the dependency, so the unit test will focus on the "Unit" to be tested. In your case, the person looks like a simple entity class, there is no need to use Mocking for it.

Upvotes: 1

Related Questions