Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking SUT itself

Sometimes I feel the desire of mocking the subject under test itself, I know it looks strange.

Here is the example. I use C#, but it doesn't matter. Imagine you have a class managing some collection. It has methods

public void Insert(int position, T element)

and

public void Delete(int position)

The logic of these methods is not very simple. Besides modifying a collection they can, for example, raise events, or subscribe for/unsubscribe from events, or acquire/release resources, or perform computations. These methods are covered with unit tests checking this functionality.

Now you add a method

public void Replace(int position, T element)
{
    Delete(position);
    Insert(position, element);
}

I am not completely sure, but to me, it’s not worth testing all those things again for this method. Instead, it makes sense to check if this method really calls the two first.

If the first two methods belonged to another class or interface, it would easy using modern mocking frameworks. But these methods belong to SUT.

Is it possible to do what I want? If not, then why? Is it an unintended flaw of the mocking approach or is it by design. If first, are there workarounds? If second, how should I design and test the described program?

like image 241
Dmitry Tashkinov Avatar asked Oct 11 '22 06:10

Dmitry Tashkinov


2 Answers

I'm not sure what framework you are using, but I was able to do this in Rhino.Mocks. Instead of instantiating my SUT, I created a stub of it (note that I am not creating a stub of the interface, but of the object itself). The stub will still run the SUT's code, but will also keep track of calls for me.

//Create a stub of my SUT, passing the constructor arguments to GenerateStub()
_sut = MockRepository.GenerateStub<SutClass>(_mockedDependency);

This allows me to assert things like...

_sut.AssertWasCalled(x => x.DoTheStuff(_argObject1, _argObject2),
                     o => o.Repeat.Once());

Pretty nifty. Now I just need to make sure I don't abuse it ;)

Edit: I should add that to test if the method DoTheStuff was called, it looks like it may need to be overridable (virtual in C#). I thought it wouldn't be necessary, but a test I wrote the other day suggests the opposite. Let me know if I'm wrong.

like image 85
Jeff B Avatar answered Oct 21 '22 07:10

Jeff B


First of all, yes it can be done, at least in FakeItEasy.

Second of all, it's probably not a good idea. I say probably because there are cases where it's at least not a very bad idea. In your example above I'd say it's probably a bad idea but I'm not sure that's a real world example. It's a bad idea since the replace method could just as well be an extension method for your class and that way it will be very easy to test.

However if you decide that it is a good idea in your case this is how you'd do it in FakeItEasy (make sure that the methods you want to assert on are virtual):

// In your set up
var sut = A.Fake<MySut>();
A.CallTo(sut).CallsBaseMethod();

// In your test of the Replace-method
A.CallTo(() => sut.Delete(thePosition)).MustHaveHappened();

I'm not sure if it's very easy to do this in other mocking frameworks but this would probably point you in the right direction.

As I said, it's probably not a good idea in most cases but I have used this technique myself and it can be useful.

like image 42
Patrik Hägne Avatar answered Oct 21 '22 06:10

Patrik Hägne