Autowired constructor not instantiating dependencies properly in Springboot - java

I have an integration which instantiates a service and that service has an Autowired dependency on a bean I'm trying to mock.
The problem is the service is getting instantiated before the autowired bean is and causing NPE. How can I ensure DependencyINeed is initialized before the MyClass in the example below?
Service
#Service
public class MyClass {
#Autowired private DependencyINeed dependency;
#Autowired
public MyClass(
#Value("${thing1}") int t1,
#Value("${thing2}") String t2) {
}
Method call yielding NPE
public class MyClass {
....
public void randomFunction() {
dependency.methodCall() <-- NPE
}
}
Test
#ContextConfiguration(classes = TestConfiguration.class)
#Import({TestConfiguration.class})
#SpringBootTest(
classes = {TestConfiguration.class, DependencyINeed.class, MyClass.class})
public class MyCoolIntegrationTest {
#Autowired private DependencyINeed dependency;
#Autowired private MyClass client;
Test Configuration
#TestConfiguration
public class MyTestConfiguration {
#MockBean private DependencyINeed dep;
#Bean
public DependencyINeed initDep() {
....
return dep;
}
}

Try to delete yout test config, and make yout Test class look like this:
#ContextConfiguration(classes = TestConfiguration.class)
#Import({TestConfiguration.class})
#SpringBootTest(
classes = {TestConfiguration.class, DependencyINeed.class, MyClass.class})
public class MyCoolIntegrationTest {
#MockBean private DependencyINeed dependency;
#Autowired private MyClass client;
#BeforeEach
public void beforeEach() {
Mockito.when(dependency.SOMEHING()).thenReturn(YOUR STUFF);
}
}

Related

Why #Autowiring a #Configuration class throws null pointer Junit5

I have a class that autowires another #ConfigurationProperties class.
#Configuration
#Data
#ConfigurationProperties("api")
public class ApiConfiguration {
private String myUrl;
}
....
Class that autowires above class ApiConfiguration
public class Services implements anotherServices {
#Autowired
private ApiConfiguration apiConfiguration;
....
#Override
public Mono<SomeClass> getClassInfo(String ..., String ...) {
return someWebClient
.get()
.uri(apiConfiguration.getRewardsBalance()) ---> **Null pointer**
Now when I autowire ApiConfiguration class, if I System.out the output I see that it's been set with whatever String I passed in, meaning My junit class is autowiring apiConfiguration class however, the actual implementation class throws a null pointer exception on apiConfiguration.
Test class
#ExtendWith(SpringExtension.class)
#ActiveProfiles("test")
#EnableConfigurationProperties(value = {ApplicationConfiguration.class,ApiConfiguration.class})
#TestPropertySource("classpath:application.properties")
#ContextConfiguration(
initializers = ApplicationContextInitializer.class)
class AccountDetailsServicesTest {
#Autowired
private ApiConfiguration apiConfiguration;
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
...
apiConfiguration.setApi("http://localhost:8080");
...

Can I inject mocks into a prototype bean with Autowired constructor?

Is it possible to inject a mock service into a prototype bean using the #Autowired constructor? I realize I could switch to setter injection but I would prefer to use the constructor if possible.
#Component
#Scope(value = "prototype")
public class Prototype {
private DependantService dependantService;
#Autowired
public Prototype(DependantService dependantService) {
this.dependantService = dependantService;
}
}
#SpringBootTest
public class TestPrototype {
#Autowired
private ApplicationContext ctx;
#Mock
private DependantService dependantService;
#Test
public void testPrototype() {
// How can I inject the mock service?
ctx.getBean(Prototype.class);
}
}
Turns out there is an overloaded version of the getBean method that accepts arguments. I would downvote my on question if I could.
#SpringBootTest
public class TestPrototype {
#Autowired
private ApplicationContext ctx;
#Mock
private DependantService dependantService;
#Test
public void testPrototype() {
Prototype p = ctx.getBean(Prototype.class, dependantService);
// Test p
}
}
If you want to speed up your unit tests, [and do true isolated unit testing,] I suggest taking a look at the #InjectMocks mockito annotation. #SpringBootTest fires up the Spring container which is pretty cumbersome.
#Controller
public class MyController {
#Inject
private Logger log;
public methodThatNeedsTesting(){
log.info("hey this was called");
}
}
#TestInstance(Lifecycle.PER_CLASS)
#ExtendWith({ MockitoExtension.class })
class MyControllerTest {
#Mock
private Logger log;
#InjectMocks
private MyController myController;
#Test
void test_methodThatNeedsTesting() throws Exception {
myController.methodThatNeedsTesting();
// myController will not throw an NPE above because the log field has been injected with a mock
}

Load dependency in webmvctest

I have a rest controller which I am trying to Unit Test:
It has a few dependencies autowired
#RestController
#RequestMapping("/test")
public class TestController {
private final Dep1 dep1;
private final Dep2 dep2;
private final Dep3 dep3;
public TestController(final Dep1 dep1,
final Dep2 dep2,
final Dep3 dep3) {
this.dep1 = dep1;
this.dep2 = dep2;
this.dep3 = dep3;
}
}
I recently added dep3
#Service
public class Dep3 {
private final IValidator validator;
public Dep3(final IValidator validator) {
this.validator= validator;
}
public void validate(final Request req) {
validator.validate(req);
}
}
Dep3 has its own Autowired Dependency IValidator
Here is my test class:
#WebMvcTest(TestController.class)
public class TestControllerTest {
#MockBean
private Dep1 dep1;
#MockBean
private Dep2 dep2;
#MockBean
private Dep3 dep3;
#Autowired
private MockMvc mockMvc;
#Test
public void someTest() throws Exception {
}
#TestConfiguration
static class InnerConfiguration {
#Bean
IValidator validator() {
return new SomeValidator();
}
}
}
For my test, I need the code to actually run the dep3.validate(..) with the implementation SomeValidator(). I am unsure how to achieve this. Perhaps I am missing an annotation?
Don't mock Dep3. Instead configure Dep3 bean in #TestConfiguration:
#TestConfiguration
static class InnerConfiguration {
#Bean
Dep3 dep3() {
return new Dep3(validator());
}
#Bean
IValidator validator() {
return new SomeValidator();
}
}
Spring will inject fully configured Dep3 into TestController
You have to configure your Mock correctly.
Something like this:
Mockito.when(dep3.validate(Mockito.any(Request.class))).thenReturn(new SomeValidator());
You can do this in your test method or in the setup method before the actual call.

Beans are not Autowired during tests (java.lang.NullPointerException)

my application normally works fine, but when I run tests, or build application by maven, application is shutting down due tests with errors java.lang.NullPointerException. I debugged it and find out my that my beans in service layer are not Autowired and they are null.
Here is my class with tests:
public class CompanyServiceSimpleTest {
private CompanyService companyService;
#Before
public void setUp() {
companyService = new CompanyServiceImpl();
}
// Here is sample test
#Test
public void testNumberOfCompanies() {
Assert.assertEquals(2, companyService.findAll().size());
}
}
companyService is initialized, but beans in it not. Here is CompanyServiceImpl:
#Service
public class CompanyServiceImpl implements CompanyService {
#Autowired
private CompanyRepository companyRepository; // is null
#Autowired
private NotificationService notificationService; // is null
#Override
public List<CompanyDto> findAll() {
List<CompanyEntity> entities = companyRepository.find(0, Integer.MAX_VALUE);
return entities.stream().map(Translations.COMPANY_DOMAIN_TO_DTO).collect(Collectors.toList());
}
// ... some other functions
}
So when is called companyRepository.find() applications crashes. Here is repository class:
#Repository
#Profile("inMemory")
public class CompanyInMemoryRepository implements CompanyRepository {
private final List<CompanyEntity> DATA = new ArrayList<>();
private AtomicLong idGenerator = new AtomicLong(3);
#Override
public List<CompanyEntity> find(int offset, int limit) {
return DATA.subList(offset, Math.min(offset+limit, DATA.size()));
}
// ... some others functions
}
I have set up profile for that service but I had that VM options in Idea:
-Dspring.profiles.active=develpment,inMemory
So it should works.
To make autowiring work it has to be a Spring integration test. You have to anotate your test class with:
#RunWith(SpringJUnit4ClassRunner.class) and #ContextConfiguration(classes = {MyApplicationConfig.class})
If it is a Spring Boot app e.g.:
#RunWith(SpringJUnit4ClassRunner.class) and #SpringBootTest(classes = {MyApp.class, MyApplicationConfig.class}, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
More on this topic: http://www.baeldung.com/integration-testing-in-spring and http://www.baeldung.com/spring-boot-testing
You are not configuring Spring in your TestClasses, so it's impossible to inject anything...
Try configurin your class with
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "path to your config xml" })
A little example:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:config/applicationContext.xml"})
public class MyTest {
#Autowired
private MyClass myInjectedClass;
#Test
public void someTest() {
assertNotNull(myInjectedClass);
}
}

Mock object method call using Spring Boot and Mockito

I am trying to write a test for this Java SpringBoot's class:
https://github.com/callistaenterprise/blog-microservices/blob/master/microservices/composite/product-composite-service/src/main/java/se/callista/microservices/composite/product/service/ProductCompositeIntegration.java
Specifically, I am trying to "mock" this method call:
URI uri = util.getServiceUrl("product");
I figured out I should "mock" the ServiceUtils object in order to do this. I tried this using the #Mock and #InjectMocks annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = ProductCompositeServiceApplication.class)
public class ProductCompositeIntegrationTest {
#InjectMocks
#Autowired
private ProductCompositeIntegration productIntegration;
#Autowired
private RestTemplate restTemplate;
#Mock
private ServiceUtils util;
private MockRestServiceServer mockServer;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockServer = MockRestServiceServer.createServer(restTemplate);
}
#Test
public void myTest() {
Mockito.when(util.getServiceUrl("product")).thenReturn(URI.create("http://localhost:8080/test"));
ResponseEntity<Iterable<Product>> products = productIntegration.getAllProducts();
}
}
But this way it still calls the original ServiceUtils object, and not the "mocked" one. Also tried without the #Autowired annotation at the ProductCompositeIntegration, but this results in a NullPointerException.
What am I doing wrong?
My main class looks like this:
#SpringBootApplication
#EnableCircuitBreaker
#EnableDiscoveryClient
public class ProductCompositeServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductCompositeServiceApplication.class, args);
}
}
The ServiceUtils object that I am trying to mock is specified in a class, annotated with Spring's #Component annotation to inject it into the other classes using #Autowired.
After a lot of trial and error I managed to solve this problem.
I dropped the
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = ProductCompositeServiceApplication.class)
annotations aboved the test class.
I marked the class that I was testing with #InjectMocks and the dependencies with #Mock:
public class ProductCompositeIntegrationTest {
#InjectMocks
private ProductCompositeIntegration productIntegration;
#Mock
private ServiceUtils util;
private MockRestServiceServer mockServer;
private RestTemplate restTemplate = new RestTemplate();
#Before
public void init() {
MockitoAnnotations.initMocks(this);
mockServer = MockRestServiceServer.createServer(restTemplate);
productIntegration.setRestTemplate(restTemplate);
}
#Test
public void someTests() {
when(util.getServiceUrl("product")).thenReturn(URI.create("http://localhost:8080/test"));
//Test code...
}
}
I'm not sure if this is the best approach ("the Spring way"), but this worked for me.
This article made it all clear to me: http://rdafbn.blogspot.be/2014/01/testing-spring-components-with-mockito.html
You have to write a FactoryBean like
public class MockitoFactoryBean<T> implements FactoryBean<T> {
private Class<T> classToBeMocked;
public MockitoFactoryBean(Class<T> classToBeMocked) {
this.classToBeMocked = classToBeMocked;
}
#Override
public T getObject() throws Exception {
return Mockito.mock(classToBeMocked);
}
#Override
public Class<?> getObjectType() {
return classToBeMocked;
}
#Override
public boolean isSingleton() {
return true;
}
}
In your test-context.xml you have to add the following lines.
<bean id="serviceUtilMock" class="MockitoFactoryBean">
<constructor-arg value="your.package.ServiceUtil" />
</bean>
If you don't use XML configuration, then you have to add the equivalent to above in your Java configuration.

Categories

Resources