Alex Alex - 5 months ago 34
Java Question

Spring @Autowired constructor causes @Value to return null when instantiated in test class

I'm using an autowired constructor in a service that when instantiated in the test class causes the @Value annotations to return null. Autowiring the dependencies directly solves the problem but the project follows the convention of using constructor based autowiring. My understanding is that instantiating the service in the test class is not creating it from the Spring IoC container which causes @Value to return null. Is there a way to create the service from the IoC container using constructor based autowiring without having to directly access the application context?

Example Service:

@Component
public class UpdateService {

@Value("${update.success.table}")
private String successTable;

@Value("${update.failed.table}")
private String failedTable;

private UserService userService

@Autowired
public UpdateService(UserService userService) {
this.userService = userService;
}
}


Example Test Service:

@RunWith(SpringJUnite4ClassRunner.class)
@SpringApplicationConfiguration(classes = {TestApplication.class})
@WebAppConfiguration
public class UpdateServiceTest {

private UpdateService updateService;

@Mock
private UserService mockUserService;

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);

updateService = new UpdateService(mockUserService);

}
}

Answer

To make @Value work updateService should be inside of spring context.

The best practice for spring framework integration tests is to include application context in test context and autowiring test source in test:

...
public class UpdateServiceTest  { 
    @Autowired 
    private UpdateService updateService;
    ...

Mock userService

Option with changing userService to protected and considering that test and source classes are in same package.

@Before
public void setUp() {
   MockitoAnnotations.initMocks(this);

   updateService.userService = mockUserService;
}

Option with reflection with Whitebox:

@Before
public void setUp() {
   MockitoAnnotations.initMocks(this);

   Whitebox.setInternalState(updateService, 'userService', mockUserService);
}
Comments