JUnit How to Mock with varying values of parameter object? - java

Following is my test code using JUnit Mockito:
#Before
public void preSetup() throws Exception {
AuditTrail auditTrail = new AuditTrail();
auditTrail.setEventType(1);
auditTrail.setEventDetail("play");
auditTrail.setEventDate(new Date());
Mockito.doReturn(auditTrail).when(auditService).addAuditTrail(auditTrail);
}
#Test
public void testaddPlayAuditRecord() {
boolean value = auditService.addPlayAuditRecord();
assertEquals(true, value);
}
And my service looks like:
#Override
public boolean addPlayAuditRecord() {
return addAuditRecord(1,"play");
}
#Override
public boolean addDeleteAuditRecord() {
return addAuditRecord(2,"delete");
}
#Override
public boolean addSearchAuditRecord() {
return addAuditRecord(3,"search");
}
private boolean addAuditRecord(String eventType, String eventDetail) {
AuditTrail auditTrail = new AuditTrail();
auditTrail.setEventType(eventType);
auditTrail.setEventDetail(eventDetail);
auditTrail.setEventDate(new Date());
AuditTrail obj = auditService.addAuditTrail(auditTrail);
}
auditService.addAuditTrail(auditTrail) makes a database call which I want to mock and return a object with values of my choice.
But this auditTrail object is built by values which are dependent on which method is calling it. They vary depending on which method is calling the addAuditRecord method. Also, we're using new Date() to get the current date object. So the date I'll be using in test will be different than what I'll use in addAuditRecord since the date is current date.
So in my test file, how do I mock this addAuditTrail method? Can such mocking be done in #Before method? The auditTrail object passed here should match the object which is actually constructed in the addAuditRecord method.
How do I do this?

Have you tried this?
Mockito.doReturn(auditTrail).when(auditService)
.addAuditTrail(ArgumentMatchers.any(AuditTrail.class));
In this way you run this rule everytime you pass an AuditTrail object, regardless his internal values.
For your Mockito version just use:
Mockito.doReturn(auditTrail).when(auditService)
.addAuditTrail(Matchers.any(AuditTrail.class));

Related

Why is my mockito code calling the real code?

I am using mockito to write a test in java in intellij. I am trying to use mockito to mock an api request,
but it still seems to be calling the real code and not using the data returned from sendRequest, causing my test to fail. Why is this?
Here is the code:
public String sendRequest(){
return "1\n" +
"2\n" +
"3";
}
#Test
public void calculateWeatherCorrectly() throws IOException {
try {
WeatherCalculator weatherCalculator = mock(WeatherCalculator.class);
when(weatherCalculator.sendWeatherRequest("London", "01-01-2020")).thenReturn(sendRequest());
assertThat(midDayWeather("London", "12-01-2020"), equalTo(1.15));
} catch (IOException e) {
e.printStackTrace();
}
}
Here is a smaller version of the method being tested:
public static Double midDayWeather(String place, String date)
throws IOException {
WeatherCalculator weatherCalculator = new WeatherCalculator();
String l = weatherCalculator.sendWeatherRequest(place, date);
String[] result = l.split("\n");
return result.length;
}
You have created a mock object with the mock() method and set it up correctly. However, you are not using the WeatherCalculator object anywhere. Your method midDayWeather() is static and will not use your mocked WeatherCalculator object created in your test method. In fact, your midDayWeather() method creates his own WeatherCalculator object (which is not mocked) and use it instead.
If your static midDayWeather() method should work with your mocked method you have to pass it as an argument. So you method should look something like this:
public static Double midDayWeather(WeatherCalculator calculator,
String place, String date) throws IOException
{
calculator.sendWeatherRequest(...);
}
Then you can pass your mocked object as an argument.

Mocking class is returning null instead of data

In my Junit test, I'm doing the following in my Junit test :
#Before
public void setUp() throws Exception {
reportQueryParams = ReportQueryParams.builder()
.id("07")
.build();
}
#Test
public void tabSerializerTest() {
MetricsSerializer mockMonth = mock(MetricsSerializer.class);
when(mockMonth.getCurrentMonth()).thenReturn("July");
String tabSeparated = mockMonth.serializeMetrics(reportQueryParams);
String expected = new StringBuilder().append("074")
.append("\t")
.append("July")
.toString();
assertEquals(expected, tabSeparated);
}
The function which I am testing:
public String serializeMetrics(final ReportQueryParams reportQueryParams) {
stringJoiner = new StringJoiner("\t");
addValueFromString(reportQueryParams.getId());
addValueFromString(getCurrentMonth());
return stringJoiner.toString();
}
public String getCurrentMonth() {
DateFormat monthFormat = new SimpleDateFormat("MMMMM");
return monthFormat.format(new Date());
}
private void addValueFromString(final String value) {
stringJoiner.add(value);
}
My ReportQueryParams class:
public class ReportQueryParams {
private String id;
}
I am getting "null" in the actual data returned and hence the test is failing. How can I fix this?
Don't mock the object you test.What you have written is "create a mock object that returns July for current month". But this mock object doesn't have real behaviour and the other methods return null.
When you test a class you mock the objects required by the class (in order to insulate behaviour) and not the actual class. Here you can create a new MetricsSerializer (by using new :) and call it's method serializeMethod and compare against the current date (instead of July).
The way you have written the class might not be the best testable way though ;)
Your problem is that you are mocking the class, then testing the mock object, rather than testing a "real" object. I can think of two possible solutions.
Use a Mockito Spy instead of a mock. This is like a mock, but it's a real object, and the methods all have their normal behaviour, instead of "no behaviour" by default. You can stub the getCurrentMonth method of your spy, to make it return what you want.
Since the real cause of your problem is the call to new Date(), you could use a time helper, instead of calling new Date() directly in your getCurrentMonth() method. I have described this technique in detail in my answer to this question

Use Powermockito to check if a private method is called or not

I would like to check if a private method of my class to test is executed or not using powermockito.
Suppose that I have this class to test:
public class ClassToTest {
public boolean methodToTest() {
//doSomething (maybe call privateMethod or maybeNot)
return true;
}
//I want to know if this is called or not during the test of "methodToTest".
private void privateMethod() {
//do something
}
}
When I test "methodToTest" I want to check if it returns the correct result but also if it executes the private method "privateMethod" or not.
Searching on other discussion I wrote this test that makes use of powermockito but it doesnt works.
public class TestClass {
#Test
testMethodToTest(){
ClassToTest instance = new ClassToTest();
boolean result = instance.methodToTest();
assertTrue(result, "The public method must return true");
//Checks if the public method "methodToTest" called "privateMethod" during its execution.
PowerMockito.verifyPrivate(instance, times(1)).invoke("privateMethod");
}
}
When I use the debugger it seems that the last line (PowerMockito.verifyPrivate...) doesn't check if the private method has been executed once during the test but instead it seems that it executes the private method itself. Furthermore the test passes but using the debugger I'm sure that the private method is not executed during the call of "instance.methodToTest()".
What is wrong?
I'd do it easier way, without PowerMockito. Consider this (it's some kind of Spy object):
public class TestClassToTest {
private boolean called = false;
#Test
public void testIfPrivateMethodCalled() throws Exception {
//given
ClassToTest classToTest = new ClassToTest() {
#Override
void privateMethod() {
called = true;
}
};
//when
classToTest.methodToTest();
//then
assertTrue(called);
}
}
This requires changing privateMethod() to package-private (but there's nothing wrong with this).
But bear in mind, that testing implementation is a bad practise and can lead to fragile tests. Instead you should test only results.

Mockito : doAnswer Vs thenReturn

I am using Mockito for service later unit testing. I am confused when to use doAnswer vs thenReturn.
Can anyone help me in detail? So far, I have tried it with thenReturn.
You should use thenReturn or doReturn when you know the return value at the time you mock a method call. This defined value is returned when you invoke the mocked method.
thenReturn(T value) Sets a return value to be returned when the method is called.
#Test
public void test_return() throws Exception {
Dummy dummy = mock(Dummy.class);
int returnValue = 5;
// choose your preferred way
when(dummy.stringLength("dummy")).thenReturn(returnValue);
doReturn(returnValue).when(dummy).stringLength("dummy");
}
Answer is used when you need to do additional actions when a mocked method is invoked, e.g. when you need to compute the return value based on the parameters of this method call.
Use doAnswer() when you want to stub a void method with generic Answer.
Answer specifies an action that is executed and a return value that is returned when you interact with the mock.
#Test
public void test_answer() throws Exception {
Dummy dummy = mock(Dummy.class);
Answer<Integer> answer = new Answer<Integer>() {
public Integer answer(InvocationOnMock invocation) throws Throwable {
String string = invocation.getArgumentAt(0, String.class);
return string.length() * 2;
}
};
// choose your preferred way
when(dummy.stringLength("dummy")).thenAnswer(answer);
doAnswer(answer).when(dummy).stringLength("dummy");
}
doAnswer and thenReturn do the same thing if:
You are using Mock, not Spy
The method you're stubbing is returning a value, not a void method.
Let's mock this BookService
public interface BookService {
String getAuthor();
void queryBookTitle(BookServiceCallback callback);
}
You can stub getAuthor() using doAnswer and thenReturn.
BookService service = mock(BookService.class);
when(service.getAuthor()).thenReturn("Joshua");
// or..
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return "Joshua";
}
}).when(service).getAuthor();
Note that when using doAnswer, you can't pass a method on when.
// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());
So, when would you use doAnswer instead of thenReturn? I can think of two use cases:
When you want to "stub" void method.
Using doAnswer you can do some additionals actions upon method invocation. For example, trigger a callback on queryBookTitle.
BookServiceCallback callback = new BookServiceCallback() {
#Override
public void onSuccess(String bookTitle) {
assertEquals("Effective Java", bookTitle);
}
};
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
BookServiceCallback callback = (BookServiceCallback) invocation.getArguments()[0];
callback.onSuccess("Effective Java");
// return null because queryBookTitle is void
return null;
}
}).when(service).queryBookTitle(callback);
service.queryBookTitle(callback);
When you are using Spy instead of Mock
When using when-thenReturn on Spy Mockito will call real method and then stub your answer. This can cause a problem if you don't want to call real method, like in this sample:
List list = new LinkedList();
List spy = spy(list);
// Will throw java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
when(spy.get(0)).thenReturn("java");
assertEquals("java", spy.get(0));
Using doAnswer we can stub it safely.
List list = new LinkedList();
List spy = spy(list);
doAnswer(invocation -> "java").when(spy).get(0);
assertEquals("java", spy.get(0));
Actually, if you don't want to do additional actions upon method invocation, you can just use doReturn.
List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));
The simplest answer is:
If you need a fixed return value on method call then we should use thenReturn(…)
If you need to perform some operation or the value need to be computed at run time then we should use thenAnswer(…)

Mocked object is null when using PowerMock/Mockito

I am trying to unit test one of my methods using PowerMock and Mockito and getting NUllPointerException for one of the objects which I have already mocked and defined behavior in my test.
This is the code I am trying to test
protected void setTabList() {
List<ActionBar.Tab> list = TabAdapter.get().getAllEnabledTabs();
listAdapter.setTabList(list);
int itemCount = list.size();
if (itemCount == 1 && list.get(0).equals(TabAdapter.KEYPAD_TAB)) {
header.setVisibility(View.VISIBLE);
listAdapter.hide();
}
}
And this is the test code
#RunWith(PowerMockRunner.class)
#PrepareForTest({Log.class, TabFragment.class, TextView.class, SystemProperties.class})
public class TabFragmentTests extends TestCase {
#Before
public void setUp() {
suppress(method(Log.class, "println_native"));
suppress(everythingDeclaredIn(TextView.class));
suppress(method(SystemProperties.class, "native_get_boolean"));
suppress(method(SystemProperties.class, "native_get", String.class));
tabFragment = new TabFragment();
listAdapter = Mockito.mock(TabList.class);
}
#Test
public void testSetTabList() {
assertNotNull(tabFragment);
assertNotNull(listAdapter);
TabAdapter instance = TabAdapter.get();
TabAdapter spy = spy(instance);
List<ActionBar.Tab> list = new ArrayList<ActionBar.Tab>();
list.add(KEYPAD_TAB);
doAnswer(new Answer<String>() {
#Override
public String answer (InvocationOnMock invocation) {
return "set Tabs";
}
}).when(listAdapter).setTabList(list);
doAnswer(new Answer<String>() {
#Override
public String answer (InvocationOnMock invocation) {
return "hide";
}
}).when(listAdapter).hide();
doReturn(list).when(spy).getAllEnabledTabs();
tabFragment.setTabList();
verify(listAdapter, times(1)).hide();
}
When I run the test and tabFragment.setTabList() is called, listAdapter in setTabList() throws NPE. I am trying to understand why listAdapter.setTabList(list) is not replaced by the "answer" API I have in the test.
I have also tried using Mockito.doNothing().when(listAdapter).setTabList(list) but that doesn't solve the issue.
Another observation is when I create a dummy getTestString(listAdapter) method in my TabFragment class and call it using tabFragment.getTestString(listAdapter) from my test passing mocked listAdapter as an argument, it doesn't through a NPE. Does that mean I have to explicitly pass mocked object to the method call?
You are overriding a method call like this:
when(listAdapter).setTabList(list);
but then you call it like this:
tabFragment.setTabList();
I don't see how that would work. setTabList(list); and setTabList(); call different methods.
I think that you forgot to add "TabAdapter" class to the "PrepareForTest" annotation :
#PrepareForTest({Log.class, TabAdapter.class, TabFragment.class, TextView.class, SystemProperties.class})

Categories