Spring ServletRegistrationBean not mapping in SPOCK tests - spring

I have got a problem with the test for my custom registrationDispatcherServlet.
I created configuration class with bean:
#Configuration
public class ServletDispatcherInitializer {
#Bean
public ServletRegistrationBean registrationDispatcherServlet(ApplicationContext parentApplicationContext) {
AnnotationConfigWebApplicationContext childApplicationContext = new AnnotationConfigWebApplicationContext();
childApplicationContext.setParent(parentApplicationContext);
childApplicationContext.register(WebApiConfig.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setApplicationContext(childApplicationContext);
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/api/v1/*");
servletRegistrationBean.setLoadOnStartup(0);
servletRegistrationBean.setName("customDispatcherServlet");
return servletRegistrationBean;
}
}
Create WebApiConfig class with some annotations:
#EnableWebMvc
#Configuration
#ComponentScan("info.pionas.rental")
public class WebApiConfig {
}
And this is my StubRestController:
#RestController
#RequestMapping("/stub")
public class StubRestController {
#GetMapping
public String test() {
return "Super";
}
}
when in test I skip prefix it works but if I add prefix it is not works
#SpringBootTest
#AutoConfigureMockMvc
class StubRestControllerTest extends Specification {
#Autowired
private MockMvc mockMvc
def "should return exist page"() {
expect:
mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/stub/test")) // not works
.andExpect(MockMvcResultMatchers.status().is(HttpStatus.OK.value()))
}
}
Any idea?
Thanks for help

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 context doesn't load my class in unittest

I can't get my unit test to load my configuration class.
My test class is annotated:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles(profiles = "test")
#ContextConfiguration (classes = ClientConfiguration.class)
public class ClientConfigurationTest { ...
ClientConfiguration.class
#ConditionalOnProperty(value = "dirt.security.oauth2client", matchIfMissing = false)
#Configuration
#PropertySource(value = "classpath:oauth2client-${spring.profiles.active:local}.properties", ignoreResourceNotFound=true)
public class ClientConfiguration {
static {
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
#Bean
#ConfigurationProperties(prefix = "dirt.security.oauth2client.client")
ClientCredentialsResourceDetails clientConfig() {
return new ClientCredentialsResourceDetails() {
#Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
};
}
#Bean
#ConfigurationProperties(prefix = "dirt")
protected DirtClientConfig dirtClientConfig() {
return new DirtClientConfig();
}
#Bean
DirtRestTemplate restTemplate() {
DirtRestTemplate dirtRestTemplate =
new DirtRestTemplate(clientConfig(),
new DefaultOAuth2ClientContext(), dirtClientConfig());
dirtRestTemplate.setErrorHandler(new RestTemplateResponseErrorHandler());
return dirtRestTemplate;
}
}
None of the 3 beans get instantiated, and when I call this, it gets a dependecy error on one of the other beans
#Test
public void clientConfig() {
DirtRestTemplate results =
(DirtRestTemplate)context
.getAutowireCapableBeanFactory()
.createBean(DirtRestTemplate.class,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE,
true);
assertNotNull(results);
}

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 boot #Autowired is not working in the servlet duriing the server startup

I have servlet whose load on startup property is '1', in this servlet I have to cache database entries during the application server startup.
In this servlet I am calling the CacheService which retrieves the db objects, its annotated with #Autowired annoatation, during the application startup the CacheService object is null.I have annotated the CacheService with #Service annotation. The #Autowired annotation is not working.
#Service
public class CacheService {
#Autowired
private IJobsService jobsServiceImpl;
public List<Jobs> getALLJobs(){
List<Jobs> alljobs = jobsServiceImpl.findAllJobs();
return alljobs;
}
}
public class StartupServlet extends HttpServlet {
#Autowired
private CacheService cacheService; -- object is null not autowired
}
Below is the main class
#EnableCaching
#EnableJpaRepositories(basePackages = {"com.example.demo.repository"})
#EntityScan(basePackages = {"com.example.demo.entity"})
#SpringBootApplication
#ComponentScan(basePackages={"com.example.demo"})
#EnableAutoConfiguration(exclude = {
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class,
org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration.class})
public class DemoApplication extends SpringBootServletInitializer implements WebApplicationInitializer{
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(DemoApplication.class);
}
#Bean
ServletRegistrationBean myServletRegistration () {
ServletRegistrationBean srb = new ServletRegistrationBean();
srb.setServlet(new StartupServlet());
srb.setUrlMappings(Arrays.asList("/path2/*"));
srb.setLoadOnStartup(1);
return srb;
}
}
Could some body help me on this...?
You should do some additional work for this. You have to talk to beanFactory-like spring component and ask it to make that particular instance an eligible bean. AutowireCapableBeanFactory should do the trick.
Here is a simple example based on code you have provided
#SpringBootApplication
public class So44734879Application {
public static void main(String[] args) {
SpringApplication.run(So44734879Application.class, args);
}
#Autowired
AutowireCapableBeanFactory beanFactory;
#Bean
ServletRegistrationBean myServletRegistration() {
ServletRegistrationBean srb = new ServletRegistrationBean();
final StartupServlet servlet = new StartupServlet();
beanFactory.autowireBean(servlet); // <--- The most important part
srb.setServlet(servlet);
srb.setUrlMappings(Arrays.asList("/path2/*"));
srb.setLoadOnStartup(1);
return srb;
}
#Bean
MyService myService() {
return new MyService();
}
public static class MyService {
String time() {
return "Time: " + System.currentTimeMillis();
}
}
public static class StartupServlet extends HttpServlet {
#Autowired
MyService myService;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
final PrintWriter writer = resp.getWriter();
writer.write(myService.time());
writer.close();
}
}
}
=>
$ curl -XGET localhost:8080/path2
Time: 1498299772141%
You're creating the servlet by using new so you need to provide its dependencies. Since you're using a mix of annotation and java code configuration you can accomplish it like this:
public class StartupServlet extends HttpServlet {
private CacheService cacheService;
public StartupServlet(CacheService cacheService) {
this.cacheService = cacheService;
}
// ... rest of servlet
}
Main class:
#Bean
ServletRegistrationBean myServletRegistration (CacheService cacheService) { // <<<--- cacheService will be provided here by Spring because it's annotated
ServletRegistrationBean srb = new ServletRegistrationBean();
srb.setServlet(new StartupServlet(cacheService));
srb.setUrlMappings(Arrays.asList("/path2/*"));
srb.setLoadOnStartup(1);
return srb;
}

Mocking beans in spring context using Spring Boot

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);
}
}

Resources