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?
Dependency injection allows unit testing, but it also allow modification of an object's behavior without altering the code of that object (open/closed principle). So, it isn't just testable code, but flexible code that results.
Unit testing is challenging when you add frameworks around your tests subjects. Dependency injection is one of those patterns supported by frameworks, that we usually need in any project.
Dependency Injection is a fundamental aspect of the Spring framework, through which the Spring container “injects” objects into other objects or “dependencies”. Simply put, this allows for loose coupling of components and moves the responsibility of managing components onto the container.
Due to this, we can inject any bean from the application context by autowiring the bean into our test class: @SpringBootTest @TestPropertySource(locations="classpath:test. properties") class TestConfigurationExampleAppTests { @Autowired private DataService dataService; ... }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With