Unit test Presenter's business logic - java

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

Related

using #InjectMocks outside #Before

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.

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

Testing with Apache Camel AdviceWith and weaveById

I am currently trying to test an existing route with Apache Camel, but I am not sure I am doing it correctly, because I don't fully understand all the concepts behind Camel.
That being said, here is what I would like to do, on the following example route :
public class TestExampleRoute extends SpringRouteBuilder {
/** The Constant ENDPOINT_EDOSSIER_IMPORT. direct:edossierImport */
public static final String ENDPOINT_EXAMPLE = "direct:testExampleEndpoint";
#Override
public void configure() throws Exception {
// #formatter:off
from(ENDPOINT_EXAMPLE).routeId("testExample")
.bean(TestExampleProcessor.class, "getImportDocumentProcess").id("getImportDocumentProcess")
.bean(TestExampleProcessor.class, "createImportDocumentTraitement").id("createImportDocumentTraitement")
.to(BaseEndpoint.LOG_MESSAGE_SHOW_ALL_MULTILINE);
// #formatter:on
}
}
The point here is just to fetch an ImportDocumentProcess and create an ImportDocumentTraitement that depends on the previous object. The ImportDocumentProcess is passes through the exchange.
Here is the processor code :
#Component("testExampleProcessor")
public class TestExampleProcessor {
/** The Constant LOGGER. */
private static final Logger LOGGER = LogManager.getLogger(TestExampleProcessor.class);
#Autowired
ImportDocumentTraitementService importDocumentTraitementService;
#Autowired
ImportDocumentProcessDAO importDocumentProcessDAO;
#Autowired
ImportDocumentTraitementDAO importDocumentTraitementDAO;
// ---- Constants to name camel headers and bodies
private static final String HEADER_ENTREPRISE = "entreprise";
private static final String HEADER_UTILISATEUR = "utilisateur";
private static final String HEADER_IMPORTDOCPROCESS = "importDocumentProcess";
public void getImportDocumentProcess(#Header(HEADER_ENTREPRISE) Entreprise entreprise, Exchange exchange) {
LOGGER.info("Entering TestExampleProcessor method : getImportDocumentProcess");
Utilisateur utilisateur = SessionUtils.getUtilisateur();
ImportDocumentProcess importDocumentProcess = importDocumentProcessDAO.getImportDocumentProcessByEntreprise(
entreprise);
exchange.getIn().setHeader(HEADER_UTILISATEUR, utilisateur);
exchange.getIn().setHeader(HEADER_IMPORTDOCPROCESS, importDocumentProcess);
}
public void createImportDocumentTraitement(#Header(HEADER_ENTREPRISE) Entreprise entreprise,
#Header(HEADER_UTILISATEUR) Utilisateur utilisateur,
#Header(HEADER_IMPORTDOCPROCESS) ImportDocumentProcess importDocumentProcess, Exchange exchange) {
LOGGER.info("Entering TestExampleProcessor method : createImportDocumentTraitement");
long nbImportTraitementBefore = this.importDocumentTraitementDAO.countNumberOfImportDocumentTraitement();
ImportDocumentTraitement importDocumentTraitement = this.importDocumentTraitementService.createImportDocumentTraitement(
entreprise, utilisateur, importDocumentProcess, "md5_fichier_example_test", "fichier_example_test.xml");
long nbImportTraitementAfter = this.importDocumentTraitementDAO.countNumberOfImportDocumentTraitement();
exchange.getIn().setHeader("nbImportTraitementBefore", Long.valueOf(nbImportTraitementBefore));
exchange.getIn().setHeader("nbImportTraitementAfter", Long.valueOf(nbImportTraitementAfter));
exchange.getIn().setHeader("importDocumentTraitement", importDocumentTraitement);
}
}
I have read a few things about AdviceWith and WeaveById and I would like to put test the state of the exchange between two pieces of route.
Here is my attempt for a processor test :
#ContextConfiguration(locations = { "classpath:/camel-context.xml" })
public class TestExampleProcessorTest extends CamelTestSupport {
#Override
protected RouteBuilder createRouteBuilder() {
return new TestExampleRoute();
}
#Override
public boolean isUseAdviceWith() {
return true;
}
#Before
public void mockEndPoints() throws Exception {
context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
weaveById("getImportDocumentProcess").replace().multicast().to("mock:catchTestEndpoint");
}
});
}
#Test
public void testAdvised() throws Exception {
MockEndpoint mockEndpoint = getMockEndpoint("mock:catchTestEndpoint");
context.start();
mockEndpoint.expectedMessageCount(1);
mockEndpoint.assertIsSatisfied();
context.stop();
}
}
One last thing : I am using Camel 2.18.0.
How can I test the state of the exchange between each piece of route ?
What am I missing ?
EDIT : Just edited the code of the the test class (Which compiles and works) BUT I get the following assertion error :
java.lang.AssertionError: mock://catchTestEndpoint Received message count. Expected: <1> but was: <0>
This adds one more question : why is the message not caught correctly ?
Thanks for your help.
Do you send any message to you testroute? I can't see that in the code. For example
template.sendBody("direct:testExampleEndpoint", "Hello World");

NPE when calling mock

I have just started with testing and I'm also using MVP pattern in my android apps.
Currently I have a presenter which uses the following android code to test if an email address is valid :
android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches()
Since it's not possible to test it with a local JVM unit test I decided to hide it behind an interface :
public interface EmailValidator {
boolean isValidEmail(CharSequence target);
}
and here's the implementation :
public class EmailValidatorImpl implements EmailValidator {
#Override
public boolean isValidEmail(CharSequence target) {
if (target == null) {
return false;
} else {
return android.util.Patterns.EMAIL_ADDRESS.matcher(target).matches();
}
}
}
So now my test code is :
public class SignUpPresenterTest {
#Mock
private SignUpMVP.View view;
#Mock
private EmailValidator validator;
private SignUpPresenter presenter;
private String email = "name#gmail.com";
private String password = "ABCDabcd";
private String username = "username";
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
presenter = new SignUpPresenter(view);
}
#Test
public void onButtonSignUpClicked() throws Exception {
when(validator.isValidEmail(email))
.thenReturn(true);
presenter.onButtonSignUpClicked(email, password, username);
verify(view).executeSignUpService();
}
}
and now I'm getting a NPE when the code above calls : EmailValidatorImpl.isValidEmail()
java.lang.NullPointerException
at com.example.signup.helpers.EmailValidatorImpl.isValidEmail(EmailValidatorImpl.java:20)
at com.example.signup.SignUpPresenter.showErrors(SignUpPresenter.java:67)
at com.example.signup.SignUpPresenter.onButtonSignUpClicked(SignUpPresenter.java:25)
at com.example.signup.SignUpPresenterTest.onButtonSignUpClicked(SignUpPresenterTest.java:43)
and my questions are : isn't this how I Should use Mockito ? Is there anything I can do to test my code and avoid NPE ?
That happens because you are mocking the EmailValidator but you are not using that object inside SignUpPresenter.
You should pass the reference in the constructor:
presenter = new SignUpPresenter(view, validator);
or in the method signature:
presenter.onButtonSignUpClicked(email, password, username, validator);
Then you presenter should be something like this:
public class SignUpPresenter {
private View view;
private EmailValidator validator;
public SignUpPresenter(View view, EmailValidator validator) {
this.view = view;
this.validator = validator;
}
private void onButtonSignUpClicked(String email, String password, String username) {
//Your code...
boolean isValid = validator.isValidEmail(email);
}
}
You should try with this, because you need to provide a real implementation of your interface
#InjectMocks
private EmailValidator validator = new EmailValidatorImpl();

Servlet JUnit test using Jmockit

I want build a unit test for a Servlet using JUnit and JMockit.
I have an ImageServlet which takes image IDs (String) as request parameters and if ID is null the servlet throws a HTTP status code 404 (not found)
for this scenario I have the test:
Unit Test:
#RunWith(JMockit.class)
public class ImageServletTest {
#Tested
private ImageServlet servlet;
#Injectable
HttpServletRequest mockHttpServletRequest;
#Injectable
HttpServletResponse mockHttpServletResponse;
#Injectable
PrintWriter printWriter;
#Injectable
ServletOutputStream servletOutputStream;
#Before
public void setUp() throws Exception {
servlet = new ImageServlet();
initMocks(null);
}
private void initMocks(final String imgId) throws Exception {
new NonStrictExpectations() {{
mockHttpServletRequest.getParameter("id");
result = imgId;
mockHttpServletResponse.getWriter();
result = printWriter;
mockHttpServletResponse.getOutputStream();
result = servletOutputStream;
}};
}
#Test
public void testImageNotFound() throws Exception {
servlet.doGet(mockHttpServletRequest, mockHttpServletResponse);
org.junit.Assert.assertTrue(mockHttpServletResponse.getStatus() == HttpServletResponse.SC_NOT_FOUND);
}
}
the problem is that my Assertion fails as mockHttpServletResponse.getStatus() always returns 0, is there a way to get the resulting Status code of the servlet using JMockit?
I'm not familiar with all the latest JMockit injection stuff, so I used JMockits support for "fakes".
#RunWith(JMockit.class)
public class ImageServletTest3 {
#Test
public void testImageNotFound() throws Exception {
ImageServlet servlet = new ImageServlet();
servlet.doGet(
new MockUp<HttpServletRequest>() {
#Mock
public String getParameter(String id){
return null;
}
}.getMockInstance(),
new MockUp<HttpServletResponse>() {
#Mock
public void sendError(int num){
Assert.assertThat(num, IsEqual.equalTo(404));
}
}.getMockInstance()
);
}
}

Categories

Resources