2

The title is self explanatory but I'll elaborate. I'm using FakeItEasy framework where I have the option to check the number of times a method have been invoked.

A.CallTo(() => foo.Bar()).MustHaveHappened();    

But by doing this I'm testing the internal behavior of my code. I'm not testing a returned value or a state change which is what a good test should do. so my question is this: is it a good practice to test the number of times a method have been called?

Tsahi
  • 445
  • 4
  • 22

1 Answers1

1

You should care about the number of times a dependency was invoked in many cases.

For example, suppose your have a service that inserts some data into some database by invoking a web service.

public interface IDataInserter
{
    void Insert(Data[] data);
}

And assume that in some cases you need to insert some 10000 items. But the web service cannot handle such volume of data in a single call. So you decide to create a decorator that will split the data into multiple chunks and send each chunk in a single request.

public class SplittingDecorator : IDataInserter
{
    private readonly IDataInserter m_DataInserter;

    public SplittingDecorator(IDataInserter data_inserter)
    {
        m_DataInserter = data_inserter;
    }

    public void Insert(Data[] data)
    {
        var chunks = 
            data
            .Select((d, i) => new {d, i})
            .GroupBy(x => x.i/50)
            .Select(x => x.Select(y => y.d).ToArray())
            .ToList();

        foreach (var chunk in chunks)
        {
            m_DataInserter.Insert(chunk);
        }
    }
}

When you want to test the SplittingDecorator class, you will create a mock for the data_inserter constructor argument.

In such test, you need to assert that the mocked IDataInserter was invoked some X times when you invoke SplittingDecorator.Insert with a data of size Y.

For example, if the data size (length of the data array) is 160 items, you want to check that the mock was invoked 4 times.

Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62
  • Yes, but what this indication actually gives you? If I'm looking from user's perspective, you don't know what the insert method did. You don't know if the output is as expected. You just know that a method have been called but you don't if it did the right thing – Tsahi Nov 14 '15 at 20:25
  • If you think about the responsibility of this decorator, its is to split the request into multiple chunks. And this is exactly what you should test. You should test that such class would split that data into multiple chunks. You test that it invoked the web service X times. You also need to check that no data were lost, i.e., all the 160 items of data have been a part of some request to the service. – Yacoub Massad Nov 14 '15 at 20:37
  • Please note that if this class did not split the data correctly, this means that it is not doing its job. So you should test for that. – Yacoub Massad Nov 14 '15 at 20:40
  • I think that what you really wanna test here is the size of the chunks list and not the number of calls to the Insert method. So what I would here is extract the logic of the chunks list to a method and then test it. That way the test will be more readable. – Tsahi Nov 14 '15 at 20:56
  • So what if there is a bug in the decorator that cause it to only send the first 50 items only (in a single request). The splitting logic might be correct, but the sending logic might not. So you still want to test that the service was invoked 4 times. – Yacoub Massad Nov 14 '15 at 20:59
  • Please note that you should only test against the public part of the class. The splitting logic it self is not part of the public part of the class. The decorated service however, is part of the public part of the class (via `IDataInserter data_inserter` in the constructor). – Yacoub Massad Nov 14 '15 at 21:01