Mocking beans in spring context using Spring Boot - spring

I'm using Spring Boot 1.3.2, and I notice problem, ComponentScan in my test class is not working. And I want to mock some of Spring Beans. Is spring boot blocking ComponentScan?
Test config class:
#Configuration
#ComponentScan(value = {"myapp.offer", "myapp.image"})
public class TestEdge2EdgeConfiguration {
#Bean
#Primary
public OfferRepository offerRepository() {
return mock(OfferRepository.class);
}
}
Test class:
#ContextConfiguration(classes=TestEdge2EdgeConfiguration.class, loader=AnnotationConfigContextLoader.class)
public class OfferActionsControllerTest extends AbstractTestNGSpringContextTests {
#Autowired
private OfferRepository offerRepository;
#Autowired
private OfferActionsController offerActionsController;
#BeforeMethod
public void setUp(){
MockitoAnnotations.initMocks(this);
}
#Test
public void saveOffer() {
//given
BDDMockito.given(offerRepository.save(any(Offer.class))).willReturn(new Offer());
//when
ResponseEntity<Offer> save = offerActionsController.save(new Offer());
//then
org.springframework.util.Assert.notNull(save);
}
}

Solution of this problem
Test config class, it's important to exclude SpringBootApplicationConfigutation and add #ComponentScan:
#ComponentScan(basePackages = "com.example", excludeFilters =
#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
value = {SpringBootApplicationConfigutation.class, MyDao.class}
)
)
#Configuration
public class TestEdge2EdgeConfiguration {
#Bean
public OfferRepository offerRepository() {
return mock(OfferRepository.class);
}
}
And test:
#SpringApplicationConfiguration(classes=TestEdge2EdgeConfiguration.class)
public class OfferActionsControllerTest extends AbstractTestNGSpringContextTests {
#Autowired
private OfferRepository offerRepository;
#Autowired
private OfferActionsController offerActionsController;
#BeforeMethod
public void resetMock() {
Mockito.reset(offerRepository);
}
#Test
public void saveOffer() {
//given
BDDMockito.given(offerRepository.save(any(Offer.class))).willReturn(new Offer());
//when
ResponseEntity<Offer> save = offerActionsController.save(new Offer());
//then
org.springframework.util.Assert.notNull(save);
}
}

Related

Why did #TestConfiguration not create a bean for my test?

My service
#Service
public class StripeServiceImpl implements StripeService {
#Override
public int getCustomerId() {
return 2;
}
}
My test
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}
The error: java.lang.NullPointerException. I had checked and the stripeService is actually null.
Since you are autowiring you need an applicationcontext so that Spring can manage the bean and then can get injected in your class. Therefore you are missing an annotation to create the applicationcontext for your testclass.
I have updated your code and it works now(with junit 5 on your classpath). In the case dat you are using junit 4 it should be #RunWith(SpringRunner.class) instead of #ExtendWith(SpringExtension.class):
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfiguration.class)
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}

Spring Profiles issue for Multiprofile

Spring Profiles doesnot works as expected. I have below two beans. First Bean I want to use for local, dev and myDevProfile. I added #Profile({"local", "dev", "mydev"}), but its not working. I am using Spring Boot 2.0.1.RELEASE
#Bean
#Profile("local")
#Qualifier("myApiClient")
public ApiClient localxApiClient() {
return new RestTemplateApiClient(baseUrl);
}
#Bean
#Profile("!local")
#Qualifier("myApiClient")
public ApiClient xApiClient() {
return new ComplexClient(baseUrl);
}
This appears to work for me:
#SpringBootTest
#ActiveProfiles("local")
public class LocalApiClientTests {
#Autowired
private ApiClient apiClient;
#Test
public void testApiClient() {
assertThat(apiClient).isInstanceOf(RestTemplateApiClient.class);
}
}
#SpringBootTest
#ActiveProfiles({"dev", "mydev"})
public class NonLocalApiClientTests {
#Autowired
private ApiClient apiClient;
#Test
public void testApiClient() {
assertThat(apiClient).isInstanceOf(ComplexClient.class);
}
}

Spring injection: #MockBean #Repository is not injected

I'm trying to #MockBean a #Repository annotated class:
#Repository
public interface ApplicationDao extends MongoRepository<Application, String> {}
I'm injecting it into a #Service annotated class:
#Service
public class AuthorizationService {
private ApplicationDao appsDao;
private List<Application> allowedApplications;
#Autowired
public AuthorizationService(ApplicationDao appsDao) {
this.appsDao = appsDao; //<<MOCKED INJECTED BEAN>>
this.fillApplications();
}
private void fillApplications() {
this.appsDao.findAll() //<<MOCKED method>>
.forEach(entry -> {
this.allowedApplications.put(entry.getName(), entry);
});
}
public bool isAuthorized(Application application) {
return this.allowedApplications
.stream()
.anyMatch(app -> app.getId().equals(application.getId()));
}
}
My test mocking configuration looks like:
#RunWith(SpringRunner.class)
#SpringBootTest()
public class GroupReferencesTest {
private #Autowired AuthorizationService;
private #MockBean ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app)); //<<FAILS>>
}
}
Nevertheless, my mocked object is not injected. I mean, when my AuthorizationService calls its injected ApplicationDao is returns an empty list instead of my mocked list.
I've tried to use #MockBean(name="applicationDao") as well. The behavior is the same.
I've also tried to configure my mocked bean using this code:
#TestConfiguration
public class RestTemplateTestConfiguration {
#Bean("applicationDao")
#Primary
public static ApplicationDao mockApplicationDao() {
ApplicationDao mock = Mockito.mock(ApplicationDao.class);
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(mock.findAll())
.thenReturn(allowedApplications);
return mock;
}
}
However, it doesn't works right.
Application class is:
public class Application {
private String id;
//setters & getters
}
Any ideas?
First things first - the type of test. Answer: Unit test.
You are starting Spring context that manages a lifecycle of AuthorizationService and then you are trying to inject mock. What really happens is that Spring IoC container is injecting a real ApplicationDao (the one managed by Spring IoC container) into the AuthorizationService.
Solution:
Manage lifecyle of AuthorizationService by your test runner (like MockitoJUnitRunner and inject ApplicationDao mock into it):
#RunWith(MockitoJUnitRunner.class)
public class GroupReferencesTest {
private #InjectMocks AuthorizationService authorizationService;
private #Mock ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app));
}
}
Working example
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {AuthorizationService.class})
public class GroupReferencesTest {
#Autowired
private AuthorizationService;
#MockBean
private ApplicationDao applicationDao;
#Test
public void test() {
//given
Mockito.when(applicationDao.findAll()).thenReturn(emptyList());
//when & then
assertTrue(authorizationService.isAuthorized(app));
}
}

Null Pointer when using #SpringBootTest

I am using spring boot 1.4,
when using the #SpringBootTest annotation for integration test, it gives a null pointer.
#RunWith(SpringRunner.class);
#SpringBootTest
public class MyControllerTest {
#Test
public void mytest {
when().
get("/hello").
then().
body("hello");
}
}
and for main class:
#SpringApplication
#EnableCaching
#EnableAsync
public class HelloApp extends AsyncConfigureSupport {
public static void main(String[] args) {
SpringApplication.run(HelloApp.class, args);
}
#Override
public Executor getAsyncExecutor() {
...
}
}
Then in my controller:
#RestController
public class HelloController {
#Autowired
private HelloService helloService;
#RequestMapping("/hello");
public String hello() {
return helloService.sayHello();
}
}
HelloService
#Service
public class HelloService {
public String sayHello() {
return "hello";
}
}
But it ways says NullPointException when for helloService when processing request.
What am I missing?
You need to mock HelloService in your test class as your controller is calling a service .Here in your case Your Test class is not aware that there is any service available or not
The following example test class might help you. In this guide from spring an example is shown how to integration test a rest controller in a spring fashion way.
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
public class HelloControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void hello() throws Exception {
mockMvc.perform(get("/hello")).andExpect(content().string("hello"));
}
}

Issues with a Spring #Configurable class not getting its dependencies autowired

I am trying to configure Load Time Weaving for my Spring Boot app to properly autowire dependencies on a #Configurable java class.
Here is my configuration/main class:
package com.bignibou;
#Configuration
#EnableAutoConfiguration(exclude = { SecurityAutoConfiguration.class, ThymeleafAutoConfiguration.class, FlywayAutoConfiguration.class })
#EnableSpringConfigured
#EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED)
#ComponentScan
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Here is how I start the application (my gradle build renamed the spring-instrument jar):
java -javaagent:build/lib/springinstrument.jar -jar myapp.jar
Here is the #Configurable class that does not get its dependencies autowired:
package com.bignibou.converter;
#Configurable
public class StringToDayToTimeSlotConverter implements Converter<String, DayToTimeSlot> {
#Autowired
private DayToTimeSlotRepository dayToTimeSlotRepository;//NOT AUTOWIRED!!
#Override
public DayToTimeSlot convert(String id) {
return dayToTimeSlotRepository.findOne(Long.parseLong(id));//NPE HERE!!
}
}
Here is where the class is instantiated (with new):
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.bignibou.controller" }, useDefaultFilters = false, includeFilters = { #Filter(type = FilterType.ANNOTATION, value = Controller.class),
#Filter(type = FilterType.ANNOTATION, value = ControllerAdvice.class) })
#Import(ApplicationControllerAdvice.class)
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
...
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new DayToTimeSlotToStringConverter());
registry.addConverter(new StringToDayToTimeSlotConverter());//INSTANTIATED HERE!
registry.addConverter(new LanguageToStringConverter());
registry.addConverter(new StringToLanguageConverter());
registry.addConverter(new AddressToStringConverter());
registry.addConverter(new StringToAddressConverter());
super.addFormatters(registry);
}
Can anyone please help figure out why StringToDayToTimeSlotConverter's dependencies are not autowired?
Very old question with at least a suggestion for a solution that I will turn into an answer so that the question can be "closed". Turn StringToDayToTimeSlotConverter into a Bean as follows:
#Bean
public class StringToDayToTimeSlotConverter implements Converter<String, DayToTimeSlot> {
#Autowired
private DayToTimeSlotRepository dayToTimeSlotRepository;
#Override
public DayToTimeSlot convert(String id) {
return dayToTimeSlotRepository.findOne(Long.parseLong(id));
}
}
Inject all available converters in WebMvcConfiguration as follows:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.bignibou.controller" }, useDefaultFilters = false, includeFilters = { #Filter(type = FilterType.ANNOTATION, value = Controller.class),
#Filter(type = FilterType.ANNOTATION, value = ControllerAdvice.class) })
#Import(ApplicationControllerAdvice.class)
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Autowired
List<Converter> converters;
#Override
public void addFormatters(FormatterRegistry registry) {
for (Converter converter : converter) {
registry.addConverter(converter);
}
super.addFormatters(registry);
}
}

Resources