Why is my mockito code calling the real code? - java

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.

Related

JUnit How to Mock with varying values of parameter object?

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

How to effective verify a method if it called during unit test with Powermock

When I used Powermock to mock a private method, and then verify it in another method's unit test, to check if it was called and with correct times. But I found I can verify whether the method was called and with the correct param, the called times of the method can be any number, however the unit test always passed. If someone can help me solve the problem. thx!
This is my source code:
public enum ConversionCommon{
INSTANCE;
...
public void getConvertTypeData(JSONObject result, JSONObject conversionData, String intent){
String uncertainty = "";
String unit1 = "";
String unit1_char = "";
if(result.has(ConversionDefine.CONVERSION_UNCERTAINTY)){
uncertainty = result.getString(ConversionDefine.CONVERSION_UNCERTAINTY);
}
if(result.has(ConversionDefine.CONVERSION_UNIT1)){
unit1 = result.getString(ConversionDefine.CONVERSION_UNIT1);
}
if(result.has(ConversionDefine.CONVERSION_UNIT1_CHAR)){
unit1_char = result.getString(ConversionDefine.CONVERSION_UNIT1_CHAR);
}
setUnitCount(conversionData, uncertainty, intent);
setDestUnits(conversionData, unit1, unit1_char);
}
}
The method getConvertTypeData() calls two methods once. The follow is my test case code:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ConversionCommon.class, LengthConversion.class })
#PowerMockIgnore("javax.management.*")
public class ConversionCommonTest{
#Before
public void setUp() throws Exception{
PowerMockito.mockStatic(LengthConversion.class);//
PowerMockito.spy(LengthConversion.class); //
}
#Test
public void should_getConvertTypeData_invoke_setUnitCount() throws Exception{
JSONObject result = new JSONObject();
JSONObject conversionData = new JSONObject();
result.put(ConversionDefine.CONVERSION_UNCERTAINTY, "3");
result.put(ConversionDefine.CONVERSION_UNIT1, "meter");
result.put(ConversionDefine.CONVERSION_UNIT1_CHAR, "centmeter");
suppress(method(ConversionCommon.class, "setUnitCount", JSONObject.class, String.class, String.class));
ConversionCommon.INSTANCE.getConvertTypeData(result, conversionData, ConversionDefine.INTENT_LENGTH_CONVERSION);
PowerMockito.verifyPrivate(ConversionCommon.INSTANCE, Mockito.times(1)).invoke("setUnitCount", Mockito.anyObject(), Mockito.anyString(), Mockito.anyString());
}
The test case can run successful but if I change the last line to ...
PowerMockito.verifyPrivate(ConversionCommon.INSTANCE, Mockito.times(100)).invoke("setUnitCount", Mockito.anyObject(), Mockito.anyString(), Mockito.anyString());
... and re-run the test case. The result is also passed. But in fact I only call the method setUnitCount only once in Refo.
The edition of test framework: mockito:1.10.19;powermock:1.6.5
How can I correct verify the private method's call times with the API PowerMockito.verifyPrivate();
You are doing right, except one thing. You're spying on enum constant. And each enums constant is separate inner class. So you have to add two things:
Enum constant to #PrepareForTest with using fullyQualifiedNames, like `#PrepareForTest(values = { ConversionCommon.class, LengthConversion.class }, fullyQualifiedNames = "com.somepackage.ConversionCommon$INSTANCE")
Create a spy for instance: PowerMockito.spy(ConversionCommon.INSTANCE)
Replace constant with spy: Whitebox.setInternalState(ConversionCommon.class, spy)
Now, you can stub the spy method as usual doNothing().when(spy, "setUnitCount");
Code snippet for some abstract singleton implement via enum:
enum
public enum Singleton {
INSTANCE;
public void doSomething(){
callPrivateMethod();
}
private void callPrivateMethod() {
}
}
test
RunWith(PowerMockRunner.class)
#PrepareForTest(value = Singleton.class, fullyQualifiedNames = "com.stackoverflow.q46212600.Singleton$INSTANCE")
public class ClassUseSingletonTest {
#Test
public void should_verify_enum_method() throws Exception {
final Singleton spy = PowerMockito.spy(Singleton.INSTANCE);
Whitebox.setInternalState(Singleton.class, spy);
doNothing().when(spy, "callPrivateMethod");
new ClassUseSingletone().doSomething("do");
PowerMockito.verifyPrivate(Singleton.INSTANCE, times(1)).invoke("callPrivateMethod");
}
}
Full example, you may find here

First stub is called when adding an additional stub

I have the following object which I want to test:
public class MyObject {
#Inject
Downloader downloader;
public List<String> readFiles(String[] fileNames) {
List<String> files = new LinkedList<>();
for (String fileName : fileNames) {
try {
files.add(downloader.download(fileName));
} catch (IOException e) {
files.add("NA");
}
}
return files;
}
}
This is my test:
#UseModules(mockTest.MyTestModule.class)
#RunWith(JukitoRunner.class)
public class mockTest {
#Inject Downloader downloader;
#Inject MyObject myObject;
private final String[] FILE_NAMES = new String[] {"fail", "fail", "testFile"};
private final List<String> EXPECTED_FILES = Arrays.asList("NA", "NA", "mockContent");
#Test
public void testException() throws IOException {
when(downloader.download(anyString()))
.thenThrow(new IOException());
when(downloader.download("testFile"))
.thenReturn("mockContent");
assertThat(myObject.readFiles(FILE_NAMES))
.isEqualTo(EXPECTED_FILES);
}
public static final class MyTestModule extends TestModule {
#Override
protected void configureTest() {
bindMock(Downloader.class).in(TestSingleton.class);
}
}
}
I am overwriting the anyString() matcher for a specific argument. I am stubbing the download() method so that it returns a value for a specific argument and otherwise throws an IOException which gets handled by MyObject.readFiles.
The weird thing here is that the second stub (downloader.download("testFile")) throws the IOException set in the first stub (downloader.download(anyString())). I have validated that by throwing a different exception in my first stub.
Can someone explain me why the exception is thrown when adding an additional stub? I thought that creating a stub does not call the method/other stubs.
The problem is that when you write
when(downloader.download("testFile")).thenReturn("mockContent");
the first thing to be called is downloader.download, which you've already stubbed to throw an exception.
The solution is to use the slightly more versatile stubbing syntax that Mockito provides. This syntax has the advantage that it doesn't call the actual method when stubbing.
doThrow(IOException.class).when(downloader).download(anyString());
doReturn("mock content").when(downloader).download("test file");
I have listed other advantages of this second syntax, in my answer here
I thought that creating a stub does not call the method/other stubs.
This assumption is wrong, because stubbing is calling the mocks methods. Your test methods are still plain java!
Since stubbing for anyString will overwrite stubbing for any specific string you will either have to write two tests or stub for two specific arguments:
when(downloader.download("fail")).thenThrow(new IOException());
when(downloader.download("testFile")).thenReturn("mockContent");
Mockito is a very sophisticated piece of code that tries its best so that you can write
when(downloader.download(anyString())).thenThrow(new IOException());
which means “when the downloaders mock download method is called with anyString argument thenThrow an IOException” (i.e. it can be read from left to right).
However, since the code is still plain java, the call sequence actually is:
String s1 = anyString(); // 1
String s2 = downloader.download(s1); // 2
when(s2).thenThrow(new IOException()); // 3
Behind the scenes, Mockito needs to do this:
register an ArgumentMatcher for any String argument
register a method call download on the downloader mock where the argument is defined by the previously registered ArgumentMatcher
register an action for the previously registered method call on a mock
If you now call
... downloader.download("testFile") ...
the downloader mock checks whether there is an action register for "testFile" (there is, since there is already an action for any String) and accordingly throws the IOException.
Your 2nd mock statement is getting overriden by the first mock statement (because both mock statements are passing a String argument). If you want to cover try as well as catch back through your mock test then write 2 different test cases.

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(…)

How to unit test a method which has a return value and dependent on my other class?

I'm a newbie at java unit testing. How to unit test a method which has a return value and dependent on my other class?
The following codes convert a ResponseBody to an object. The parser.fromJson(json, type) and decodeToJson(value) are my custom mthods.
How should I unit test the method convert(ResponseBody)?
public class MyConverter<T> {
public MyConverter(JsonParser parser, Type type, Cipher cipher) {
this.parser = parser;
this.type = type;
this.cipher = cipher;
}
public T convert(ResponseBody value) throws IOException {
String json;
if (cipher == null) {
json = value.string();
} else {
json = decrypt(value);
}
return parser.fromJson(json, type);
}
public String decrypt(ResponseBody value) {
//Just decrypt the ResponseBody to String.
...
}
}
I already have some test codes. Here is my test case.
#Test
public void testConvert_withCipher() throws Exception {
converter = spy(new MyConverter(mockParser, mockType, null));
ResponseBody dummyResponse = ResponseBody.create(MediaType.parse("application/json"), "{text:'Dummy response'}");
converter.convert(dummyResponse);
verify(converter).decrypt(eq(dummyResponse));
verify(mockParser).fromJson(anyString(), eq(mockType));
}
I only verify the vital dependent mock objects were interacted with correctly. Should I verify the returned value?
Hope someone can help me, thanks!
You can use any of the Mocking Frameworks like Mockito or JMock to mock the Response.
You don't have to verify the actual value returned from JsonParser since you are not writing the Unit Test for JsonParser but your class.
If you want to verify the number of times any of your mock has been called then you can do something like this:
verify(converter, Mockito.times(1)).decrypt(eq(dummyResponse));
This will fail in case your mock has not been called at all or is called more than one time.

Categories