Loading...

September 15, 2010

Private Spring Dependency Injections for Unit Testing

If we want to unit test a Spring managed bean with a private field that is annotated with for example the @Autowired annotation, we must do something special. Normally we cannot access the private field to assign for example a stub implementation for testing, because we have to use the public setter method. But Spring allows the use of the @Autowired annotation on a private field. And that means we don't have a public setter method. We must use org.springframework.test.util.ReflectionTestUtils.setField() to assign a new value to the field. We pass the object which contains the private field, the field name and value to the method and our value is assigned to the private variable. So we can use this method to assign a stub implementation to the field and use it for testing.

// Class to test: src/main/java/com/mrhaki/spring/MyService.java
package com.mrhaki.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyService {
    @Autowired
    private MessageService messageService;

    public String say(String name) {
        return messageService.getMessage() + name;
    }
}
// Support class used in MyService: src/main/java/com/mrhaki/spring/MessageService.java
package com.mrhaki.spring;

import org.springframework.stereotype.Component;

@Component
public class MessageService {
    public String getMessage() {
        return "Hello, ";
    }
}

We want to unit test MyService and provide a mock implementation for MessageService, so we only test the code in MyService. We use Mockito to provide the mock functionality. And because messageService is a private field we must use ReflectionTestUtils.setField() method.

// Test class for testing MyService: src/test/java/com/mrhaki/spring/MyServiceTest.java
package com.mrhaki.spring;

import org.junit.Test;
import org.springframework.test.util.ReflectionTestUtils;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class MyServiceTest {
    @Test
    public void sayHi() {
        MessageService messageService = mock(MessageService.class);
        when(messageService.getMessage()).thenReturn("Hi, ");

        MyService myService = new MyService();
        // Inject mock into private field:
        ReflectionTestUtils.setField(myService, "messageService", messageService);

        assertEquals("Hi, mrhaki", myService.say("mrhaki"));
    }
}

As a bonus we can use the following Gradle build script to compile and test these classes:

apply plugin: 'java'

repositories {
  mavenCentral()
}

dependencies {
  compile 'org.springframework:spring-context:3.0.4.RELEASE'
  testCompile 'junit:junit:4.8.1', 'org.mockito:mockito-all:1.8.5', 'org.springframework:spring-test:3.0.4.RELEASE'
}

Project is also available on GitHub: BlogSamples/SpringTestInjection.