TDD – Mock.Throw Interface Call Verification Technique

First of all I did not know what to call this post, so it is what it is. If you have any better suggestions leave a comment!

Often I find myself writing a class which ties multiple classes together. I like to call these controllers. Therefore using a MVVMC (Model-View-ViewModel-Controller) pattern which is a combination of MVVM and MVC as I believe they suit each other very well.

One problem that bugs when I am doing this using a TDD approach is that my interface call verification methods fail because of either NotImplementedException or NullReferenceException because as I test the first interface call, the rest is not yet implemented, or the mocks return null.

Rant

For the TDD purists out there, no I do not write a non compilable test first. I develop using the following cycle:

  1. Think about what I need and how I would test it
  2. Create an empty class to represent what I need
  3. Create an empty method
  4. Add comments of what this method should do
  5. Change the comments to empty implementations (often another method which throws new NotImplementedException)
  6. Write a test for the first fake implementation
  7. Code the implementation
  8. Repeat 6-7 until no empty implementations left.
  9. Repeat steps 1-8 for each interface I used.

I guess you can call it Test Driven Design, rather than Development. Maybe one day it will change, who knows, but currently that is how I enjoy coding the most, makes me most productive as well as churn out decent quality code. I guess that is an idea for another blog post 😀

Rant Over

The Technique

[Test]
[ExpectedException(typeof(MockCalled))]
public void ProcessData_CallsWorker()
{
    var list = new List {1};
 
    // Setup worker
    _worker.Setup(w => w.DoWork(list))
           .Throws(); // Technique
 
    // Act
    _controller.ProcessData(list);
}

 The Reason

The reason for adding throws is to stop the flow of the program as soon as it hits that mock. I often use this when I want to verify a call was made to a mock, and I don’t want to test the remaining logic or flow of the class under test.

 

Method Under Test

 

The above logic can be represented by the following code:

internal void ProcessData(List data)
{
    var newData = _worker.DoWork(data);
 
    if (newData.Count == 0)
        throw new NotImplementedException(); // Do Something else
 
    SaveData(newData);
}

Having such a method, my first test would be to make sure my worker gets called. The conventional way of testing this would be something along these lines (I am using Moq, but most Mocking frameworks are similar)

[Test]
public void ProcessData_CallsWorker()
{
    var list = new List {1};
 
    // Setup worker
    _worker.Setup(w => w.DoWork(list))
        .Verifiable();
 
    // Act
    _controller.ProcessData(list);
 
    _worker.VerifyAll();
}

But using this method, the code blows up with a NullReferenceException.

NullReference

Yes you could make the worker.DoWork(list) return a list but that would just make the test throw an NotImplementedException as neither of the other paths are implemented yet.

A better option is to make the mocked worker.DoWork(list) throw an exception:

_worker.Setup(w => w.DoWork(list))
    .Throws(new MockCalled());

You then let the MockCalled exception bubble up the call stack, and get handled by you inside your test:

try
{
    _controller.ProcessData(list); // Will throw when calls worker
}
catch (MockCalled)
{
}

You should throw a custom exception ( I have used MockCalled : Exception ) so that you know for a fact that when you receive a MockCalled exception, it could of only come from your mocked method.

If your testing framework allows for annotating a test with ExpectedType (NUnit and MSTest do, haven’t tried any others), then this becomes even cleaner:

[Test]
[ExpectedException(typeof(MockCalled))]
public void ProcessData_CallsWorker()
{
    var list = new List {1};
 
    // Setup worker
    _worker.Setup(w => w.DoWork(list))
        .Throws();
 
    // Act
    _controller.ProcessData(list);
}

In the above method, I wrapped the Throws(new MockCalled()) in an extension method .Throws()  for Moq as below:

public static void Throws(this ISetup mock)
    where TMock : class
{
    mock.Throws(new MockCalled());
}

 Or you could go even further and wrap the Setup call as well:

public static ISetup ThrowsOn(this Mock mock, Expression> expression) 
    where T : class
{
    return mock.Setup(expression).Throws();
}

 Giving you a slightly neater interface:

[Test]
[ExpectedException(typeof(MockCalled))]
public void ProcessData_CallsWorker()
{
    var list = new List {1};
 
    // Setup worker
    _worker.ThrowsOn(w => w.DoWork(list));
 
    // Act
    _controller.ProcessData(list);
}

 Other Usages

Imagine the following scenario

Same Class Usage

This represents a scenario where you want to test that another method on the class under test was called. The usual way of testing something like this would be to mark your ProcessData() method as public virtual, and then Mock the class under test verifying  that the ProcessData method was called.

public virtual List ProcessData(List data) { ... }
 
[Test]
public void Iteration_HasData_CallsProcessData()
{
    // Setup repo
    var list = new List {1};
    _repo.Setup(r => r.GetData()).Returns(list);
 
    _mock.Setup(x => x.ProcessData(list))
        .Verifiable();
 
    // Act
    _mock.Object.Iteration();
 
    // Assert
    _mock.VerifyAll();
}

There are 2 issues with that:

  1. You have to make the ProcessData method public virtual so that Moq can provide an implementation that registers the call.
  2. DataChanged logic will throw a NullReferenceException if it depends on the result of ProcessData, so you have to return a valid result from ProcessData.

The first point has never sat well with me, so this is where you can again use this technique.

The second point, well thats a pain each time, so rather than setting up a verifiable virtual implementation for ProcessData that return valid data for the method to progress gracefully why not make it throw the MockCalled exception?

[Test]
[ExpectedException(typeof(MockCalled))]
public void Iteration_HasData_CallsProcessDataThrow()
{
    // Setup repo
    var list = new List {1};
    _repo.Setup(r => r.GetData()).Returns(list);
    // Setup mock
    _mock.ThrowsOn(x => x.ProcessData(list));
        
    // Act
    _mock.Object.Iteration();
}

 This makes the test a bit cleaner, but there is still a flaw which does not sit well with me. That you have to mark the method as public virtual. This is probably something that I could take a look at and implement in Moq, but I will leave that for another day. At the moment what I have been doing which is working quite well, is making the first logical interface interaction throw the exception.

In the scenario above, the first call which happens right at the start of ProcessData is the IWorker.DoWork(), so I can make this method throw the exception, knowing that it should get to there gracefully at which point the exception will be thrown.

This allows the method to stay private or internal, and does not need to be virtual.

[Test]
[ExpectedException(typeof(MockCalled))]
public void Iteration_HasData_CallsProcessDataWhichCallsWorker()
{
    // Setup repo
    var list = new List {1};
    _repo.Setup(r => r.GetData()).Returns(list);
    // Setup Worker
    _worker.ThrowsOn(x => x.DoWork(list));
        
    // Act
    _controller.Iteration();
}

As always you can find the code @ GitHub on codePerf/20150319-TddMockThrowInterfaceCallVerificationTechnique

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

This site uses Akismet to reduce spam. Learn how your comment data is processed.