2

I have to write Unit test for Web Service in Spring-boot which should perform testing from Controller and also flow into Service class. I am using @Mock annotation for Service class and @InjectMock for Controller, therefore the application flow never goes inside Service class,( it returns a null).

Without the @Mock annotation on Service class, I receive a null point exception.

I don't want to Mock the Service class,I want to test the Service class as well with this same test unit.

This is my REST Controller.

 @RestController
 public class AddressController {
 @Autowired
 private GetAddressService getAddressService;

@RequestMapping(value=ApplicationConstant.ADDRESS_URI,method=RequestMethod.G    ET,produces = { ApplicationConstant.APP_RESP_TYPE })
public @ResponseBody SampleResponse getAddress(
        @RequestParam(value="id",required=true) String hcId,
        @RequestParam(value="mbrNbrbr",required=true) String mbrNbr,
        ){

    System.out.println("Request ID in Controller :"+Id);
    String responseid = getAddressService.getAddress(Id);

    SampleResponse smapleResp = new SampleResponse();
    System.out.println("Response ID in Controller :"+Id);
    smapleResp.setResponseid(responseid);
    return smapleResp;

This is my Service Class

 @Service
public class GetAddressServiceImpl implements GetAddressService {
@Override
public String getAddress(String id) {

    System.out.println("ID in Service : " + id);
    return id;
}
}

I have an Abstract test class which extends to Abstract Controller test class and Finally my Address Controller Test class which has the @Test methods.

Abstarct Test class:

 @RunWith(SpringJUnit4ClassRunner.class)
 @SpringApplicationConfiguration(classes = Application.class)
 public abstract class AbstractTest {
  }

Abstarct Controller Test class:

@WebAppConfiguration 
public abstract class AbstractControllerTest extends AbstractTest {

//mockmvc stimulates Http interactions
protected MockMvc mockMvc; 

@Autowired
protected WebApplicationContext webApplicationContext;


protected void setUp(){
    mockMvc =   MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}


protected void setUp(AddressController addressController){
    mockMvc = MockMvcBuilders.standaloneSetup(addressController).build();
}
}

Finally My Address Test class:

   @TestExecutionListeners
    public class AddressMockControllerTest extends AbstractControllerTest  {

    @Mock
    private GetAddressService getAddressService;

    @InjectMocks
    private AddressController addressController;

    private String MockURI ="/v1/legacy/member/Contact/Address? id=55555&mbrNbr=20&id=ABC&productid=1FGQ&sourceid=STAR&addressuid=adasdsa";

    @Before
    public void setUp(){
        MockitoAnnotations.initMocks(this);
        setUp(addressController);       
        }


    @Test
    public void test(){
        System.out.println("In Unit test");

    }

    @Test
    public void testgetAddress() throws Exception {


     System.out.println("In Unit test");

     MvcResult result =  this.mockMvc.perform(
                   MockMvcRequestBuilders.get(MockURI)
                  .accept(MediaType.APPLICATION_JSON))
                  .andReturn(); 


     String content = result.getResponse().getContentAsString();

        System.out.println("In Unit test and content is " + content);   
    }

Boot Main Class:

 public class Application extends SpringBootServletInitializer{

public static void main(String[] args) {
    SpringApplication.run(ApplicationInitializer.class, args);
}

@Override
protected final SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
    return application.sources(ApplicationInitializer.class);
}

Application Initializer:

    @Configuration

@EnableAutoConfiguration
@ComponentScan(value={"com.ABC"})
@EnableConfigurationProperties
public class ApplicationInitializer {

    @Bean
    @ConditionalOnMissingBean(RequestContextListener.class)
    public RequestContextListener requestContextListener() {
        return new RequestContextListener();
    }

    @Bean
    public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
        ServletRegistrationBean registration = new ServletRegistrationBean(
                dispatcherServlet);
        registration.addUrlMappings("/");
        return registration;
    }

    @Bean
    public ServletRegistrationBean dynamicLogbackLevelServletRegistration() {

        return new ServletRegistrationBean(new DynamicLogbackLevelServlet(),"/loglevel");

    }


    @Order(Ordered.HIGHEST_PRECEDENCE)
    public FilterRegistrationBean contextFilterRegistrationBean() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        RequestFilter contextFilter = new RequestFilter();
        registrationBean.setFilter(contextFilter);
        registrationBean.setOrder(1);
        return registrationBean;
    }


    @Bean
    public ApplicationContextProvider applicationContextProvider(){
        return new ApplicationContextProvider();
    }

}
av37
  • 21
  • 1
  • 5

2 Answers2

0

Not sure if this will work but based on another SO post: https://stackoverflow.com/a/32294564/1499549

It looks like you shouldn't use the standaloneSetup() if you are using the runner.

public void setup() {
    mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}

Then remove the @InjectMocks annotation and replace it with @Autowired.

//@Mock
//private GetAddressService getAddressService;

//@InjectMocks
@Autowired
private AddressController addressController;

private String MockURI ="/v1/legacy/member/Contact/Address?id=55555&mbrNbr=20&id=ABC&productid=1FGQ&sourceid=STAR&addressuid=adasdsa";

@Before
public void setUp(){
    setUp();       
}

@Test
public void test(){
    System.out.println("In Unit test");
}
Community
  • 1
  • 1
Shawn Clark
  • 3,330
  • 2
  • 18
  • 30
  • @ShwanClark I have tried this earlier as well, Didn't work. In this case, It doesn't even start the Tests it seems. Since I have used TestExecutionListeners, it starts looking for ProfileValueSourceConfiguration but does not proceeds after that – av37 Aug 19 '16 at 05:06
  • I haven't worked with `@TestExecutionListeners` annotation before but based on the docs it looks like you aren't actually leveraging any listeners as you don't have them defined on that annotation. I did find another SO answer that talks about it: http://stackoverflow.com/a/27389768/1499549. I am wondering if you should add the `DependencyInjectionTestExecutionListener` to that annotation? – Shawn Clark Aug 19 '16 at 05:38
0

BTW, Spring Boot now has built in support for mocking and spying beans based on @MockedBean annotation. Maybe you want to look into it.

luboskrnac
  • 23,973
  • 10
  • 81
  • 92