Affichage des articles dont le libellé est mock. Afficher tous les articles
Affichage des articles dont le libellé est mock. Afficher tous les articles

samedi 23 février 2008

"Unit Integrated Tests" for integrator objects

Whether I use interaction based testing or state based testing I usually write "real" unit tests in the sense that only one real object is involved (the SUT, System Under Test) and only stubs and mocks are used for the fixture. It usually is the only way to easily get a good code coverage (or at least to easily specifically cover some parts of the code )

However, Lately, when testing Facade or Adapter objects he seemed to me that the unit tests for these objects were :
- too complicated
- too...useless

For most Facade or Adapter objects :
- They're stateless, so let's forget state based testing, we must use mocks
- They're highly coupled to the contract of the adapted objects (by definition of a Facade or of an Adapter)

This kind of class does nothing clever, they basically chain one or multiples calls. They may have bug though if they do not respect the contracts of the adapted classes.

So a unit test for this kind of class depends more on the contract of the mocked objects, than on the behavior of the class under test. A very clear test smell.

Even worse, the fixtures for the mocks are going to closely mimick the code of the SUT (if a method of a Facade calls an object A and then an object B, the fixture for the test on mocks and stubs will tell the exact same thing).

In this specific case the unit test does not provide an orthogonal view of the behavior implemented by the code (the usual value of a unit test) ; it is the exact same view. If I make a wrong assumption on the contract of the adapted objects, I'm going to make the same exact mistake both in the test and then in the code (TDDly speaking)

The problem basically is that the job of this kind of objects is to integrate other objects in the system. So he seemed to me that it is very hard to try to test an integration behavior in isolation.

That's why, now, when I must deal with objects that heavily depend on the contract of the collaborating objects but do not do anything complicated, "integrator objects", I use integrated tests.

However when I encounter an object that heavily depend on the contract of the collaborating objects and does many complicated things, it just means that it is too hard to test, I refactor.

vendredi 28 décembre 2007

EasyMock and methods with side effects

I really like EasyMock, but was disappointed to not see any explanation in the documention about how to simulate the modification of an argument of a method with side effects.

I thought that maybe I could write a custom argument matcher that modifies the argument (even if it seems weird to implement a side effect on the matches method of the IArgumentMatcher)

Actually, it was confirmed by this brilliant article about a Generic Custom Argument Matching in EasyMock

samedi 6 octobre 2007

TDD : state-based testings VS behavior-base testing

Using TDD to write my code I'm still trying to find when I should use mock objects or just test against the whole cluster of objects. That's the difference between state-based testing (no mocks) and behavior-based testing (using mocks) explained in this brilliant article by Martin Fowler : Mocks Aren't Stubs

I'm sure that both technics are useful and I switch from one technic to an other depending on the complexity of the objects I'm testing.

  • State-based testing (no mock) tend to increase the amount of integration test between objects, so is better suited to tests clusters of object with complex interaction

  • Behaviour-based testing (with mocks) tend to increase the test coverage on a given object as it is easier to control the test environment of the object under test


Using mocks objects tend to create more work, but the more I use them the more I detect bugs in my code that would very hard, or impossible to detect with state-based testing.

Last time it happened it allowed me to see that an external object was called and was not supposed to be called (because the mock was called and warned me that it was an unexpected call)

I would have never been able to detect this call with state base testing because :

  • It did not change the state of the object under test

  • It did not change the state of the external object


However the call to the real external object is very CPU intensive and would have harmed the performance. Behavior based testing allowed me to see this, it would have been undetected with state-based testing.