Search code examples
javaspringunit-testing

Unit test in Spring: injecting a dependency into a component under test


I have a very simple rest controller:

@RestController
public class MyController {
    @Autowired
    public Logger logger;

The logger dependency gets injected via the following configuration:

@Configuration
public class MyConfig {
    @Bean
    public Logger logger() {
        return LoggerFactory.getLogger(MyController.class);
    }

If I run the Spring application that contains the controller then everything works fine. However, I cannot manage to achieve this dependency injection when running my unit tests. In this case I have the following test configuration:

@Configuration
@Profile("test")
public class MyTestConfig {
    @Bean
    public Logger logger() {
        return LoggerFactory.getLogger(MyCOntroller.class);
    }

And this is the relevant part of my unit tests code:

@RunWith(MockitoJUnitRunner.class)
@ContextConfiguration(classes = MyTestConfig.class)
@ActiveProfiles("test")
public class MyContollerTest {

However the logger object does not get "autowired" in MyController (note that I do not want to mock the logger object), which results in a null pointer reference.

What am I missing?


Solution

  • A unit test shouldn't use any Spring configuration. You should simply instantiate your component, and inject dependencies (usually fake ones) manually.

    You used field injection, which makes it a bit harder. With constructor injection, all you would need to do is

    Logger logger = LoggerFactory.getLogger(MyController.class);
    MyController controller = new MyController(logger);
    

    Mockito can help injecting fake dependencies for you, though, even when using field injection, thanks to the @Mock, @Spy and @InjectMocks annotations:

    @Spy
    private Logger logger = LoggerFactory.getLogger(MyController.class);
    
    @InjectMocks
    private MyController controller;
    
    @Before
    public void prepare() {
        MockitoAnnotations.initMocks(this);
    }
    

    That said, if I'm not mistaken, you're not using @RunWith(SpringJUnit4ClassRunner.class), so your test runner doesn't know anything about Spring, and thus doesn't create or use any Spring configuration.