using #InjectMocks outside #Before - java

I'm creating the base for my unit testing project( Spring boot rest controller) and I'm having a problem passing #InjectMocks value because it's only evaluated in #Before and therefore a nullpointer is thrown when i try to access it outside
Some tips to get around the problem please?
Thank you very much
Ps : Any other advices on best practices or something i did wrong for unit testing regarding my current base class test will be appreciated as well
Class to test (rest controller)
#RestController
#RequestMapping("/management")
#Api(description = "Users count connections", produces = "application/json", tags = {"ConnectionManagement API"})
public class ConnectionManagementControllerImpl implements ConnectionManagementController {
#Autowired
private ConnectionManagementBusinessService connectionManagementBusinessService;
#Override
#PostMapping(value = "/countConnectionsByInterval" , consumes = MediaType.TEXT_PLAIN_VALUE , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
#ApiOperation(value = "count all users connections by interval")
public ResponseEntity<List<ConnectionsCountDto>> countConnectionsByInterval(#RequestBody String format) {
List<ConnectionsCountDto> connectionManagement = connectionManagementBusinessService.countConnectionsByInterval(format);
return new ResponseEntity<List<ConnectionsCountDto>>(connectionManagement, HttpStatus.OK);
}
Abstract base test
public abstract class AbstractBaseTest<C> {
public MockMvc mockMvc;
private Class<C> clazz;
private Object inject;
protected abstract String getURL();
protected final void setTestClass(final Class<C> classToSet, final Object injectToSet) {
clazz = Preconditions.checkNotNull(classToSet);
inject = Preconditions.checkNotNull(injectToSet);
}
#Before
public void init() throws Exception {
MockitoAnnotations.initMocks(clazz);
mockMvc = MockMvcBuilders.standaloneSetup(inject).build();
}
protected MockHttpServletResponse getResponse(MediaType produces) throws Exception {
MockHttpServletResponse response = mockMvc.perform(
get(getURL()).
accept(produces)).
andReturn().
getResponse();
return response;
}
protected MockHttpServletResponse postResponse(String content , MediaType consumes , MediaType produces) throws Exception {
MockHttpServletResponse response = mockMvc.perform(
post(getURL()).
content(content).
contentType(consumes).
accept(produces)).
andReturn().
getResponse();
return response;
}
}
Test class
#RunWith(MockitoJUnitRunner.class)
public class ConnectionManagementControllerImplTest extends AbstractBaseTest<ConnectionManagementControllerImpl>{
#Mock
private ConnectionManagementBusinessService connectionManagementBusinessServiceMocked;
#InjectMocks
private ConnectionManagementControllerImpl connectionManagementControllerMocked;
public ConnectionManagementControllerImplTest() {
super();
setTestClass(ConnectionManagementControllerImpl.class , connectionManagementControllerMocked); // null pointer there
}
#Test
public void countConnectionsByInterval() throws Exception {
// given
given(connectionManagementBusinessServiceMocked.countConnectionsByInterval(Mockito.anyString()))
.willReturn(new ArrayList<ConnectionsCountDto>());
// when
MockHttpServletResponse response = postResponse("day" , MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON_UTF8);
// then
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
}
#Override
protected String getURL() {
return "/management/countConnectionsByInterval";
}

This works as intended. However, you can setup mocks manually and inject them inside ConnectionManagementControllerImplTest constructor (before calling setTestClass(...)):
public ConnectionManagementControllerImplTest() {
super();
connectionManagementBusinessServiceMocked = Mockito.mock(ConnectionManagementBusinessService.class);
connectionManagementControllerMocked = new ConnectionManagementControllerImpl();
connectionManagementControllerMocked.setConnectionManagementBusinessService(connectionManagementBusinessServiceMocked);
setTestClass(ConnectionManagementControllerImpl.class, connectionManagementControllerMocked);
}
Do not forget to remove #Mock and #InjectMocks annotations. Btw you can even remove #RunWith(MockitoJUnitRunner.class) in that case.
UPDATE: Both the constructor of test class and "init" method annotated with #Before are executed for each test. The difference is that Mockito annotations are processed between constructor and #Before method invocations.
So you can slightly change your code in order to achieve a positive result:
Create "init" method (annotated with #Before) inside ConnectionManagementControllerImplTest and move setTestClass() into it from the constructor (in that particular case you can also remove the whole constructor because it would contain only super() invocation).
Add super.init() after setTestClass() line (otherwise "init" method in the parent class will be ignored by JUnit).
(Optional) you could also remove #Before annotation from the "init" method in the parent class if your tests are written in the same manner.
The example of code refactored in that way:
public abstract class AbstractBaseTest<C> {
public MockMvc mockMvc;
private Class<C> clazz;
private Object inject;
protected abstract String getURL();
protected final void setTestClass(final Class<C> classToSet, final Object injectToSet) {
clazz = Preconditions.checkNotNull(classToSet);
inject = Preconditions.checkNotNull(injectToSet);
}
#Before //this annotation can be removed
public void init() throws Exception {
MockitoAnnotations.initMocks(clazz); //this line also can be removed because MockitoJUnitRunner does it for you
mockMvc = MockMvcBuilders.standaloneSetup(inject).build();
}
protected MockHttpServletResponse getResponse(MediaType produces) throws Exception {
MockHttpServletResponse response = mockMvc.perform(
get(getURL()).
accept(produces)).
andReturn().
getResponse();
return response;
}
protected MockHttpServletResponse postResponse(String content , MediaType consumes , MediaType produces) throws Exception {
MockHttpServletResponse response = mockMvc.perform(
post(getURL()).
content(content).
contentType(consumes).
accept(produces)).
andReturn().
getResponse();
return response;
}
}
#RunWith(MockitoJUnitRunner.class)
public class ConnectionManagementControllerImplTest extends AbstractBaseTest<ConnectionManagementControllerImpl> {
#Mock
private ConnectionManagementBusinessService connectionManagementBusinessServiceMocked;
#InjectMocks
private ConnectionManagementControllerImpl connectionManagementControllerMocked;
//constructor can be removed
public ConnectionManagementControllerImplTest() {
super();
}
#Before
public void init() throws Exception {
setTestClass(ConnectionManagementControllerImpl.class, connectionManagementControllerMocked);
super.init();
}
#Test
public void countConnectionsByInterval() throws Exception {
// given
given(connectionManagementBusinessServiceMocked.countConnectionsByInterval(Mockito.anyString()))
.willReturn(new ArrayList<ConnectionsCountDto>());
// when
MockHttpServletResponse response = postResponse("day", MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON_UTF8);
// then
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
}
#Override
protected String getURL() {
return "/management/countConnectionsByInterval";
}
}
P.S. I'd prefer the former approach, but if you don't want to have a setter for ConnectionManagementBusinessService, you can choose the latter. I've tested both of them and the result was the same.

Related

When try to test post() rest endpoint see: json can not be null or empty

If I try to test the post() endpoint, I see:
java.lang.AssertionError: No value at JSON path "$.firstName"
Caused by: java.lang.IllegalArgumentException: json can not be null or empty
But with the test for the get() all work fine.
And in the postTest() the result for status is correct.
Where is my mistaker?
Is it correct way to test the rest controller in this style?
#RunWith(MockitoJUnitRunner.Silent.class)
public class Temp {
private final Employee successfullyRegisteredEmployee = new Employee(2L, "Iven");
private final Employee employeeGetById = new Employee(2L, "Iven");
#Mock
private EmployeeServiceImpl serviceMock;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(new EmployeeControllerImpl( serviceMock))
.build();
}
#Test
public void getTest() throws Exception {
when(serviceMock.getEmployee(2L)).thenReturn(employeeGetById);
mockMvc.perform(get("/employee/get/2"))
.andExpect(status().is(200))
.andExpect(content().json(("{'firstName':'Iven'}")));
verify(serviceMock).getEmployee(2L);
}
#Test
public void postTest() throws Exception {
String json = "{\n" +
" \"firstName\": \"Iven\"\n"
"}";
when(serviceMock.register(employeeForRegister)).thenReturn(successfullyRegisteredEmployee);
mockMvc.perform( MockMvcRequestBuilders
.post("/employee/register")
.content(json)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is(201))
.andExpect(jsonPath("$.firstName", Matchers.is("Iven")));
}
}
#RestController
#RequestMapping("/employee")
public class EmployeeControllerImpl implements EmployeeController {
private final EmployeeService service;
public EmployeeControllerImpl(EmployeeService service) {
this.service = service;
}
#PostMapping(path = "/register",
consumes = "application/json",
produces = "application/json"
)
public ResponseEntity<Employee> registerEmployee(#Valid #RequestBody Employee employee) {
Employee registeredEmployee = service.register(employee);
return ResponseEntity.status(201).body(registeredEmployee);
}
}
Seems like problem could be with when(serviceMock.register(employeeForRegister)).thenReturn(successfullyRegisteredEmployee);.
Did you try to have breakpoint on return ResponseEntity.status(201).body(registeredEmployee); to check if registeredEmployee is actually filled?
If it's empty then try replacing mock with when(serviceMock.register(any())).thenReturn(successfullyRegisteredEmployee); and if it works that means either equals() method is not overridden for Employee or comparison just fails.

How to write mockito junit for the method below:

Help
#Override
public String postRequestinTransactionService(String data) {
RequestTransaction request = new RequestTransaction(data.getClass().getName(), data);
HttpEntity<RequestTransaction> entity = new HttpEntity<RequestTransaction>(request);
ResponseEntity<String> response = restTemplate.exchange(this.urlTransactions, HttpMethod.POST, entity,
String.class);
return response.getBody();
}
Here is barebone test class for you. You can write test case and if you have specific problem then ask question.
#RunWith(MockitoJUnitRunner.class)
public class YourClassNameTest{
#InjectMocks
YourClassUnderTest myClass;
private String data;
#Before
public void setUp() throws Exception {
//prepare you data here
// any other mock action you can set here
}
#Test
public void testPostRequestinTransactionService() throws Exception {
//Write you test here
String result=myClass.postRequestinTransactionService(data);
assertThat("result should be blablabla", result, is("blablabla");
}

Unit test Presenter's business logic

I'm trying to unit test the code of my Presenter. As you can see below in the code I'm making a Retrofit request and if the response is successful I call a method from the View.
Code of my Presenter I want to test :
#Override
public void onLoadChatrooms(String accountId, String pageNum) {
getChatroomsService.getChatrooms(apiToken, createRequestBodyForGetChatroomsRequest(accountId, pageNum))
.enqueue(new Callback<GetChatroomsServiceResponse>() {
#Override
public void onResponse(Call<GetChatroomsServiceResponse> call, Response<GetChatroomsServiceResponse> response) {
if (response.isSuccessful()) {
view.showData(Arrays.asList(response.body().getChatRoomsArray()));
}
}
#Override
public void onFailure(Call<GetChatroomsServiceResponse> call, Throwable t) {
}
});
}
And here is the test I wrote :
#Mock
private ChatMVP.View view;
#Mock
private GetChatroomsService getChatroomsService;
#Mock
private RequestBody requestBody;
#Mock
private Call<GetChatroomsServiceResponse> call;
#Captor
private ArgumentCaptor<Callback<GetChatroomsServiceResponse>> callback;
#Mock
private List<GetChatroomsResponseNestedItem> chatroomsResponseNestedItems;
private String accountId = "14";
private String apiToken = "someToken";
private ChatPresenter chatPresenter;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
chatPresenter = new ChatPresenter(view, getChatroomsService, apiToken);
}
#Test
public void onLoadChatrooms() throws Exception {
when(getChatroomsService.getChatrooms(apiToken, requestBody))
.thenReturn(call);
chatPresenter.onLoadChatrooms(accountId, "0");
verify(call).enqueue(callback.capture());
callback.getValue().onResponse(call, getResponse());
verify(view).showData(chatroomsResponseNestedItems);
}
The problem is that I'm getting a NPE for line :
chatPresenter.onLoadChatrooms(accountId, "0");
The exact error message is :
java.lang.NullPointerException
at my.package.main.fragments.chat.ChatPresenter.onLoadChatrooms(ChatPresenter.java:40)
at my.package.main.fragments.chat.ChatPresenterTest.onLoadChatrooms(ChatPresenterTest.java:70)
where line 40 for ChatPresenter is : .enqueue(new Callback<GetChatroomsServiceResponse>() {
Anyone can help with that ? I tried checking if Presenter is null and that's not the problem.
EDIT :
ChatPresenter's constructor :
class ChatPresenter implements ChatMVP.Presenter {
private ChatMVP.View view;
private GetChatroomsService getChatroomsService;
private String apiToken;
#Inject
ChatPresenter(ChatMVP.View view, GetChatroomsService getChatroomsService, #Named("Api-Token") String apiToken) {
this.view = view;
this.getChatroomsService = getChatroomsService;
this.apiToken = apiToken;
}
and GetChatroomsService :
interface GetChatroomsService {
#POST("getchatrooms")
Call<GetChatroomsServiceResponse> getChatrooms(#Query("api_token") String apiToken, #Body RequestBody requestBody);
}
The problem here is that the mocked method getChatrooms() in getChatroomsService returns a null. The most likely reason for this is that the parameters given in your production code do not match the parameters in your mock configuration.
I for myself use the any*() matcher when configuring the mocks and verify the parameters passed in by the production code explicitly which saves me from non descriptive NPEs like this.
#Test
public void onLoadChatrooms() throws Exception {
when(getChatroomsService.getChatrooms(anyString(), any(RequestBody.class)))
.thenReturn(call);
chatPresenter.onLoadChatrooms(accountId, "0");
verify(call).enqueue(callback.capture());
callback.getValue().onResponse(call, getResponse());
verify(getChatroomsService).getChatrooms(apiToken,requestBody);
verify(view).showData(chatroomsResponseNestedItems);
}

Write Junit test cases for rest web service by calling it by path

I have a jersey web service. I want to write test cases for it.
My service is
#Path(value = "/mock")
#Component
public class MockService
{
private static Log log = LogFactory.getLog(MockService.class);
#POST
#Path(value = "/{mockrequest:ABCD}")
#Produces(MediaType.JSON)
public Response mockOKResponse(#Context ContainerRequestContext request, #PathParam("mockrequest") EnumMockService mockService)
{
return Response.ok().build();
}
#GET
#Path(value = "/{mockrequest}")
#Produces("application/pdf")
public Response mockProducesPDF(#Context ContainerRequestContext request, #PathParam("mockrequest") EnumMockService mockService)
{
MockAccountTable testccount = jdbcTestAcountDao.getTestAccountResponseBlob(mockService.toString());
byte[] responseBlob = testccount != null ? testccount.getResponseBlob() : null;
return Response.ok(responseBlob).build();
}
}
I am planing to write test case for this.Which calls specific method based on the specific reuest.
#RunWith(MockitoJUnitRunner.class)
public class TestMockService
extends TestCaseSrs
{
private MockService mockService = new MockService();
#Override
#Before
public void prepare()
throws Exception
{
MockitoAnnotations.initMocks(this);
}
#Test
public void testGetIncreasedHardwares()
{
//dynamically call method based on request
}
}
I am not sure how to set request type here to call method accordingly rather than calling method directly.
It would be great if some one can help me with the approach.

Testing Spring #MVC annotations

I ran into a problem the other day where a #Valid annotation was accidentally removed from a controller class. Unfortunately, it didn't break any of our tests. None of our unit tests actually exercise the Spring AnnotationMethodHandlerAdapter pathway. We just test our controller classes directly.
How can I write a unit or integration test that will correctly fail if my #MVC annotations are wrong? Is there a way I can ask Spring to find and exercise the relevant controller with a MockHttpServlet or something?
I write integration tests for this kind of thing. Say you have a bean with validation annotations:
public class MyForm {
#NotNull
private Long myNumber;
...
}
and a controller that handles the submission
#Controller
#RequestMapping("/simple-form")
public class MyController {
private final static String FORM_VIEW = null;
#RequestMapping(method = RequestMethod.POST)
public String processFormSubmission(#Valid MyForm myForm,
BindingResult result) {
if (result.hasErrors()) {
return FORM_VIEW;
}
// process the form
return "success-view";
}
}
and you want to test that the #Valid and #NotNull annotations are wired correctly:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"file:web/WEB-INF/application-context.xml",
"file:web/WEB-INF/dispatcher-servlet.xml"})
public class MyControllerIntegrationTest {
#Inject
private ApplicationContext applicationContext;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private HandlerAdapter handlerAdapter;
#Before
public void setUp() throws Exception {
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
this.handlerAdapter = applicationContext.getBean(HandlerAdapter.class);
}
ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
final HandlerMapping handlerMapping = applicationContext.getBean(HandlerMapping.class);
final HandlerExecutionChain handler = handlerMapping.getHandler(request);
assertNotNull("No handler found for request, check you request mapping", handler);
final Object controller = handler.getHandler();
// if you want to override any injected attributes do it here
final HandlerInterceptor[] interceptors =
handlerMapping.getHandler(request).getInterceptors();
for (HandlerInterceptor interceptor : interceptors) {
final boolean carryOn = interceptor.preHandle(request, response, controller);
if (!carryOn) {
return null;
}
}
final ModelAndView mav = handlerAdapter.handle(request, response, controller);
return mav;
}
#Test
public void testProcessFormSubmission() throws Exception {
request.setMethod("POST");
request.setRequestURI("/simple-form");
request.setParameter("myNumber", "");
final ModelAndView mav = handle(request, response);
// test we're returned back to the form
assertViewName(mav, "simple-form");
// make assertions on the errors
final BindingResult errors = assertAndReturnModelAttributeOfType(mav,
"org.springframework.validation.BindingResult.myForm",
BindingResult.class);
assertEquals(1, errors.getErrorCount());
assertEquals("", errors.getFieldValue("myNumber"));
}
See my blog post on integration testing Spring's MVC annotations
Sure. There's no reason why your test can't instantiate its own DispatcherServlet, inject it with the various items which it would have in a container (e.g. ServletContext), including the location of the context definition file.
Spring comes with a variety of servlet-related MockXYZ classes for this purpose, including MockServletContext, MockHttpServletRequest and MockHttpServletResponse. They're not really "mock" objects in the usual sense, they're more like dumb stubs, but they do the job.
The servlet's test context would have the usual MVC-related beans, plus your beans to test. Once the servlet is initialized, create the mock requests and responses, and feed them into the servet's service() method. If request gets routed correctly, you can check the results as written to the mock response.
In upcoming spring 3.2 (SNAPSHOT available) or with spring-test-mvc (https://github.com/SpringSource/spring-test-mvc) you can do it like this:
first we emulate Validation as we do not want to test the validator, just want to know if validation is called.
public class LocalValidatorFactoryBeanMock extends LocalValidatorFactoryBean
{
private boolean fakeErrors;
public void fakeErrors ( )
{
this.fakeErrors = true;
}
#Override
public boolean supports ( Class<?> clazz )
{
return true;
}
#Override
public void validate ( Object target, Errors errors, Object... validationHints )
{
if (fakeErrors)
{
errors.reject("error");
}
}
}
this is our test class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration
public class RegisterControllerTest
{
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Autowired
#InjectMocks
private RegisterController registerController;
#Autowired
private LocalValidatorFactoryBeanMock validator;
#Before
public void setup ( )
{
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
// if you want to inject mocks into your controller
MockitoAnnotations.initMocks(this);
}
#Test
public void testPostValidationError ( ) throws Exception
{
validator.fakeErrors();
MockHttpServletRequestBuilder post = post("/info/register");
post.param("name", "Bob");
ResultActions result = getMockMvc().perform(post);
// no redirect as we have errors
result.andExpect(view().name("info/register"));
}
#Configuration
#Import(DispatcherServletConfig.class)
static class Config extends WebMvcConfigurerAdapter
{
#Override
public Validator getValidator ( )
{
return new LocalValidatorFactoryBeanMock();
}
#Bean
RegisterController registerController ( )
{
return new RegisterController();
}
}
}

Categories

Resources