21

I have a question about the usage of SpringJUnit4ClassRunner. For pure Junits or Unit Test cases should we use Spring based annotations such as @Autowired along with SpringJUnit4ClassRunner or should we use only the MockitoJUnitRunner instead with the @RunWith annotation at the top of the Test class?

I mean replacing

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-applicationContext.xml" })

with just

@RunWith(MockitoJUnitRunner.class)

at the top of the class. It works for me.

In Junits we normally do not make any external calls such as calls to DB or call to some other web service. We have to mock these external calls using @Mock annotations on this service objects. And then create a real object of the class that we are testing and that depends on these mocks. We can then use @InjectMocks on the real object so that it will be injected with the mocked objects.

Example Service-A->Calls->Service-B->Calls->Service-C

While testing A we should mock Service B & while testing Service-B we should mock Service-C.

Some code Snippet

@RunWith(MockitoJUnitRunner.class)
public class TestServiceA {
    @Mock
    B mockObj;

    @InjectMocks
    A realObj;

    @Test
    public void testServiceA() {
    .....
    .....
    }
}       

So, I feel for Unit test cases we need not rely on Spring container to provide us the instance of the class we are testing.

Please give your suggestions.

Using SpringJUnit4ClassRunner.class instead of MockitoJUnitRunner.class

Stefan Birkner
  • 24,059
  • 12
  • 57
  • 72
Ayaskant
  • 459
  • 1
  • 5
  • 11
  • Your test doesn't contain anything that would require Spring's intervention, so obviously you don't need it. – Sotirios Delimanolis Jun 28 '15 at 15:54
  • @SotiriosDelimanolis - Thanks for your reply. This is actually a dummy code that is similar to my project's code. Actually at the start it had SpringJUnit4ClassRunner.class & ContextConfiguration({ "classpath:test-applicationContext.xml" }) at the top of the class & Autowired annotations on both A & B objects. There were no mocking. I removed all of them. So basically I want to know whether this mocking is the correct way to do Junits. Do Spring test framework also provide support for mocking objects. Asa shown here I am using Mockito library to mock objects. – Ayaskant Jun 28 '15 at 16:05
  • Also thinking in another way - Do we really need SpringJUnit4ClassRunner and Spring libraries in Junits? – Ayaskant Jun 28 '15 at 16:06
  • Possibly related: http://stackoverflow.com/questions/10906945/mockito-junit-and-spring – jaco0646 Jun 28 '15 at 16:09
  • 2
    You may want to use spring profiles to declare mock DB-related stuff. In this case you'll still be able to test your spring configuration (integration testing). For unit testing you don't need spring, go for MockitoJUnitRunner. – Konstantin Pavlov Jun 28 '15 at 17:07
  • @kpavlov - Yes thats what i wanted to know. I agree with your point. For Junits we do not need Spring. We can achieve the mocking by using MockitoJUnitRunner. Thanks – Ayaskant Jun 29 '15 at 07:36
  • To be more precise: For Unit Tests we don't need Spring, not for "Junits". You may use TestNG instead of JUnit and use any of that frameworks as a harness for Integration and even System Integration Tests. – Konstantin Pavlov Jun 29 '15 at 10:20

2 Answers2

15

If you try to simply unit test a class without the dependencies, like you describe, there is no need for the SpringJUnit4ClassRunner. This runner is able to generate a complete Spring context with (mock) objects you can define in your (test) application context configuration. With this mechanism the SpringJUnit4ClassRunner is much slower than the regular MockitoJUnitRunner.

The SpringJUnit4ClassRunner is very powerful for integration test purposes.

I default start with the MockitoJUnitRunner and if I reach the limits of this runner, for instance because I need to mock constructors, static methods or private variables, I switch to PowerMockJUnitRunner. This is for me a last resort as it normally tells the code is ‘bad’ and not written to be tested. Other runners are normally not necessary for isolated unit tests.

Michael Piefel
  • 18,660
  • 9
  • 81
  • 112
Sven
  • 2,343
  • 1
  • 18
  • 29
1

Building on Sven's answer, Let us say that you needed to test an assembly of classes while mocking out bits that go to the database, or call an external service, you would look to run the test with SpringJUnit4ClassRunner.
If you were trying to test a Single Java Class as a Unit, mocking out both the integration bits and local collaborators, then running the test with MockitoJUnitRunner is sufficient and faster as well.