Times ago I added some new functionalities to a Spring-based web application.
After some changes a unit test failed. The cause was a missing bean which stopped the auto-wiring process while Spring was loading the application context.
The test declared its own application contest, by using the annotation
@Configuration on a static inner class; there were some mocked beans, so I added the missing bean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Then I changed other classes adding other auto-wired beans, new methods, and the like, till when the same test that had failed before failed again! The cause was the same that had happened before: a missing bean. Clearly the missing bean was one of those I just added.
That brittle test was getting quite annoying. Why a unit test should ever fail when changes occurs in classes different from the tested one? Shouldn’t a unit test have to test a class in Isolation? Yes it should, more precisely the FIRST properties a unit test should have are:
I guess the problem with this test was a not clear comprehension of injection techniques. In fact the test in its first implementation was isolated in practice, because it used mock objects injected by
@RunWith(SpringJUnit4ClassRunner.class). Unfortunately this implementation was not isolated in theory too, because of the auto-wiring mechanism enabled by
@RunWith(SpringJUnit4ClassRunner. If the class under test evolved it would be wired with every field annotated with
@Autowired loosing isolation and gaining integration.
Even if in the Spring documentation there’s actually written unit and integration tests:
Spring TestContext Framework offers full integration with JUnit 4 through a custom runner (supported on JUnit 4.12 or higher). By annotating test classes with @RunWith(SpringJUnit4ClassRunner.class) or the shorter @RunWith(SpringRunner.class) variant, developers can implement standard JUnit 4 based unit and integration tests and simultaneously reap the benefits of the TestContext framework such as support for loading application contexts, dependency injection of test instances, transactional test method execution, and so on.
the «Spring JUnit 4 Runner» sub-section is under the «Integration Test» section, not under the «Unit Test» one.
In the end I isolated the test injecting mock objects, without any auto-wiring mechanism, by using the awesome Mockito framework for unit tests:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18