Mockito verify not working on a spied object - java

I am trying to use verify in a unit test to verify a method gets called on an object that is spied. I can verify the method is actually being called via a log statement and stepping through the code with a debugger. yet a verify(Object,1).method() call reports "Wanted but not invoked:" Also with the assertion uncommented mockTransferService.getCurrentTask() is returning null while again I can verify with the debugger that it is getting set.
Test code is shown below
#Test
public void testInitialPermitGranted() throws Exception {
Config mockConfig = mock(Config.class);
doReturn(path).when(mockConfig).getRequiredStringProperty(Config.WORK_DIR);
mockTransferService = spy(new TransferServiceImpl(mockServiceConnection, mockConfig,
Executors.newSingleThreadScheduledExecutor()));
doReturn(true).when(mockTransferService).doStartTransfer(any());
mockTransferService.enqueueTransfer(mockTransferTask);
Thread.sleep(1000);
//Assert.assertEquals(mockTransferTask, mockTransferService.getCurrentTask());
verify(mockTransferService,times(1)).startTransfer(any());
}
}
Method that is being tested is shown below
#Override
public boolean startTransfer(TransferTask transferTask) {
LOG.debug("StartTransferCalled");
setCurrentTask(transferTask);
return doStartTransfer(transferTask);
}
I'm pretty new to mockito and obviously I am missing something.

Related

Java unit test - exception not being thrown

Trying to write a test that will call my method, when that method makes a call to another method we will throw a custom exception i have made. Here i have simplified it all
2 functions
public MyJsonResponse hello() {
MyJsonResponse response = new MyJsonResponse();
response.setErrorMessage("1");
response.setStatus("some status");
response.setData("1");
response.setHttpResponse(200);
try{
hi();
return response;
}catch (MyServiceException e) {
response.setErrorMessage(e.getMessage());
response.setStatus("error creating");
response.setData("2");
response.setHttpResponse(e.getResponseStatus());
return response;
}
}
public String hi() throws MyServiceException{
LOG.error("Exception");
return "yea";
}
The test I have written is this
#Test
public void myTest() throws Exception {
given(service.hi()).willAnswer( invocation -> { throw new MyServiceException("abc msg",511); });
MyJsonResponse actual = service.hello();
Assert.assertNotNull(actual);
assertEquals(511, actual.getHttpResponse());
}
But unfortunately the result is as follows
java.lang.AssertionError:
Expected :511
Actual :200
Please, be sure that you are using a spy as you want to use the actual code for some methods of your mocked service and just stubbing specific methods of it. Please, see for instance this related SO question about the subject.
Also, consider modifying your test definition to use willThrow instead of willAnswer: as pointed out by #eis, you can still use the later, but the former is more straightforward.
Your code will look similar to this:
#Test
public void myTest() throws Exception {
MyService service = spy(MyService.class);
willThrow(new MyServiceException("abc msg",511))
.given(service)
.hi()
;
// As pointed out by #eis, you can still use willAnswer
// willAnswer(
// invocation -> { throw new MyServiceException("abc msg",511);}
// )
// .given(service)
// .hi()
// ;
MyJsonResponse actual = service.hello();
Assert.assertNotNull(actual);
assertEquals(511, actual.getHttpResponse());
}
regarding what you explain and what your code look like, I am not sure if I have well understood.
Thus, if you want that, your hi() : function throws an exception.
You have to make it first throws an exception. Take a look at code below!
public String hi() throws MyServiceException{
/*LOG.error("Exception");//No don't just log, throw a real exception as below*/
throw new MyServiceException("text here, if your constructor support it or nothing otherwise")
/*return "yea";//Nothing to return? we have just break the code by throwing the exception above*/
}
After that, please be very sure that your 'MyServiceException.getHttpResponse()' will really return 511
For this test to make sense, your hi() call should be done calling another service that you stub/mock in your test class. You're not doing that, so this approach won't work.
You wrote "the real method that hi represents does a lot", so it's about time you extract that to another service.

Can a mockito spy return stub value?

I want to test this class, so it will shows me that I call ws with right params:
class MyService {
public static boolean sendEmail(MyWebService ws) {
if (!ws.sendCustomEmail("me#example.com", "Subject", "Body")) {
throw new RuntimeException("can't do this");
}
// ... some more logic which can return false and should be tested
return true;
}
}
Is there a way to combine mockito spy and thenReturn? I like how spy will show actual methods calls and not just simple message about assertionFailed.
#Test
void myTest() {
MyService spyWs = Mockito.spy(MyWebService.class);
// code below is not working, but I wonder if there is some library
verify(spyWs, once())
.sendCustomEmail(
eq("me#example.com"),
eq("Subject"),
eq("here should be another body and test shou")
)
.thenReturn(true);
MyService::sendEmail(spyWs);
}
What I want as a result is error message showing me the difference between parameters that expected and actual like usual spy's:
Test failed:
sendCustomEmail(eq("me#example.com"), eq("Subject"), eq("here should be another body and test should show diff")) was never called
sendCustomEmail(eq("me#example.com"), eq("Subject"), eq("Body")) was called, but not expected
Expected:
I know I can do just stub and then test for exception, but thats will not show the difference in parameters
When using a Spy, use the doReturn().when() syntax. Also verify after the set-up:
MyService spyWs = Mockito.spy(MyWebService.class);
doReturn(true).when(spyWs).sendCustomEmail(any(), any(), any());
MyService::sendEmail(spyWs);
verify(spyWs, once())
.sendCustomEmail(
eq("me#example.com"),
eq("Subject"),
eq("here should be another body and test shou")
);
// assert that sendMail returned true;
Frankly i dont think you need to verify here, just a boolean assertion would be enough but thats up to you.

Working of Mockito's verify and argument captor

I'm trying to test the following method
public void saveToMultipleSources(MyObject myObject)
{
if (myObject.isOfSomeType()) {
firstDAO.saveObject(myObject);
myObject.setContent(null);
}
secondDAO.saveObject(myObject);
}
The test I wrote was
#Test
public void testSaveFeature()
{
//initialize all objects
obj.saveToMultipleSources(myObject); //myObject has a valid content.
Mockito.verify(firstDAO).saveObject(myObject);
myObject.setContent(null);
Mockito.verify(secondDAO).saveObject(myObject);
}
But on running, I get the error that expected and actual arguments differ for the verify statement of firstDAO. The expected was an object with valid content but actual arguments invoked are with Content set as null. I tried the exact same thing with ArgumentCaptor as well, but got the same results.
Can someone explain why does Mockito behave this way? I tried logging the entire object and can see valid Content being set just before I call the firstDAO.
Also how do I go about testing this?
//initialize all objects
obj.saveToMultipleSources(myObject); //myObject has a valid content.
Mockito.verify(firstDAO).saveObject(myObject);
The problem is that setting the objects content to null is a side effect of your method. In consequence Mockito compares the recorded parameter (having valid content) with the object modified by your method (having content already set to null).
In that case, how can I test this? – Abhilash Panigrahi
In the test Make myObject a Mockito.spy() and prevent the execution of setContent():
#Test
public void testSaveFeature()
{
//initialize all objects
MyObject spyOfMyObject = Mockito.spy(myObject);
doNothing().when(spyOfMyObject).setContent(null); // special null matcher may be needed...
obj.saveToMultipleSources(spyOfMyObject);
Mockito.verify(firstDAO).saveObject(spyOfMyObject);
Mockito.verify(spyOfMyObject).setContent(null);
Mockito.verify(secondDAO).saveObject(spyOfMyObject);
}
But you most likely want to be sure that myObject.setContent(null);
is called before econdDAO.saveObject(myObject);`...
#Test
public void testSaveFeature()
{
//initialize all objects
MyObject spyOfMyObject = Mockito.spy(myObject);
doNothing().when(spyOfMyObject).setContent(null);
obj.saveToMultipleSources(spyOfMyObject);
Mockito.verify(firstDAO).saveObject(spyOfMyObject);
InOrder inOrder = Mockito.inOrder(spyOfMyObject,secondDAO);
inOrder.verify(spyOfMyObject).setContent(null);
inOrder..verify(secondDAO).saveObject(spyOfMyObject);
}

JUnit4 - Test if method does nothing

How can I test if a method does nothing. For example I have a static method that throws an exception if the given string-argument is null or empty (it's meant for argument-validation). Right now my tests look like this:
#Test
public void notNullOrEmpty_doesNothingIfValueIsNotNullOrEmpty() {
Require.notNullOrEmpty(Generate.randomString());
assertTrue(true); // <- this looks very ugly
}
#Test(expected = IllegalArgumentException.class)
public void notNullOrEmpty_throwsExceptionIfValueIsNull() {
Require.notNullOrEmpty(null);
}
#Test(expected = IllegalArgumentException.class)
public void notNullOrEmpty_throwsExceptionIfValueIsEmpty() {
Require.notNullOrEmpty("");
}
How can I make the first test to pass without calling assertTrue(true), there is a Assert.fail() is there something like an Assert.pass()?
EDIT:
Added missing (expected = IllegalArgumentException.class) to 3rd test
You have just to remove the assert in the first method.
#Test
public void notNullOrEmpty_doesNothingIfValueIsNotNullOrEmpty() {
Require.notNullOrEmpty(Generate.randomString());
// Test has passed
}
If the test method runs completely then it means it pass with success. Look at Eclipse junit output:
Update: as an additional comment, if you use Mockito framework you can leverage verify method to verify that a method was called X times. For instance, I used something like this:
verify(cmAlertDao, times(5)).save(any(CMAlert.class));
In your case, since you are testing static methods, then you might find useful using PowerMock which allows you to verify static methods (since Mockito doesn't). And you can use verifyStatic(...).
You should add #Test(expected = YourException.class) annotation.
Try to add to the first test:
#Test
public void notNullOrEmpty_doesNothingIfValueIsNotNullOrEmpty() {
String str = Generate.randomString();
Require.notNullOrEmpty(str);
assertNotNull(str);
}
and probably to you have better to rename it to notNullOrEmpty_doesNothingIfValueIsNotNullOrNotEmpty because you are testing it for not empty value.
A unit test must assert which is expected in the behavior of the method.
If in your specification, when your call notNullOrEmpty()no exception must be thrown when the data is valid and an exception must be thrown when the data is not valid so in your unit test you must do no assertion when the data is valid since if it doesn't success, a exception will be thrown and the test will so be in failure.
#Test
public void notNullOrEmpty_doesNothingIfValueIsNotNullOrEmpty() {
Require.notNullOrEmpty(Generate.randomString());
}

Why does this JUnit assertion fail if method executed on same line?

I have a simple JUnit test. It fails, unless I have called the relevant function previously.
FAILS:
#Test public void isTotalSuccess(){
writer.calculateStats();
Assert.assertFalse(writer.isTotalSuccess());
}
PASSES and displays "TotalSuccess is false":
#Test public void isTotalSuccess(){
writer.calculateStats();
// One additional line here
System.out.println("TotalSuccess is " + writer.isTotalSuccess());
Assert.assertFalse(writer.isTotalSuccess());
}
I don't understand why this is happening, since usually nested methods/functions are evaluated first, before their enclosing function.
Please explain why the test fails unless the method being tested has already been called once. Is this behaviour specific to JUnit, or have I missed something really obvious?
More information:
These tests are part of WriterTest, which is testing Writer
writer is declared as a field of WriterTest with private static Writer writer = new Writer();
writer.isTotalSuccess() is a very simple method:
public boolean isTotalSuccess() {
if (total == success){
return true;
}
return false;
}

Categories