Mockito: Intercept any methods that return a type - mockito

I've an interface like this:
public interface ICustomer extends IEnd<Customer> {
String getId();
ICustomer id(String id);
ICustomer email(String email);
ICustomer description(String description);
}
I need to mock any methods which returns an ICustomer regardless of parameters.
When these methods are called, the self called ICustomer have to be returned.
Any ideas?

To do this you need a custom Answer class:
public class CustomerAnswer implements Answer {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Class retType = invocation.getMethod().getReturnType();
if (ICustomer.class.isInstance(retType)) {
return invocation.getMock();
}
// provide default logic here -- override with "when()" calls.
return null;
}
}
Then create your mock, specifying the default behavior:
Foo mockCustomer = mock(ICustomer.class, new CustomerAnswer());
Add, when() statements for other methods that need to be stubbed.
But as I commented in the OP, be sure you actually want to mock this class before you go thru all the trouble. Only mock when it will make the test code simpler. If you have some simple implementation of the interface that is just a POJO with fluent API (no side-effects, no complicated dependencies or injections), there is probably no need to mock it. Instead use a real instance, because the real instance already returns the original object.
If you need to verify() on the ICustomer object, then use a #Spy of a real instance of a ICustomer.

Related

Mock a call to a mocked class with functional interface parameter

I have this method that I need to mock:
public static void myMethod(Supplier<String> supplier, boolean flag) {
// ...
supplier.get();
// ...
}
I need to mock this method which receives a Supplier, and I would like to mock it by just calling the given Supplier. So I did like this:
Mockito.when(myMockedClass.myMethod(ArgumentMatchers.<Supplier<Integer>> any(),
ArgumentMatchers.anyBoolean())).thenAnswer(invocation -> {
Supplier<Integer> command = invocation.getArgument(0);
return command.get();
});
This works, but I am asking if there is a shorter way to do this.

Mock constructor of a class

I am writing test class for my java class. I am using Junit5 with Mockito.
I am using Junit5 which isnt compatible with Power Mockito so I am using Mockito only.
I have class Emp which have function findSalary like below and EmpProfileClient is initialized at constructor.
Class Emp {
......
public void findSalary(empId) {
...
TaxReturn taxReturn = new TaxReturn(EmpProfileClient);
int value = taxReturn.apply(new TaxReturnRequest.withEmpId(empId))
.returnInRupee();
...
}
}
When I am writing the test case, I mocked EmpProfileClient, but since we are creating TaxReturn in a method, How I can mock TaxReturn.apply so I can write the expectation to get the value as per my choice which I set in the test class?
If you want to mock this, the TaxReturn class should be an injected bean in the Emp class. Add an injection framework (like Spring) and inject the TaxReturn class. In the test you write you can inject a Mock instead of the real class. See #InjectMocks annotation of the mockito framework.
If I understood your question correctly(you are looking for mocking taxReturn.apply) I'd suggest next:
First. Refactor your taxReturn instantiation(as it is would be much easier to mock method behavior in comparison for trying to mock local variable)
public class EmpService {
public int findSalary(Integer empId) {
//...
// It's doesn't matter what the actual empProfileClient type is
// as you mocking creation behavior anyway
Object empProfileClient = null;
TaxReturn taxReturn = createClient(empProfileClient);
int value = taxReturn.apply(new TaxReturnRequest().withEmpId(empId))
.returnInRupee();
//...
return value; // or whatever
}
protected TaxReturn createClient(Object empProfileClient) {
return new TaxReturn(empProfileClient);
}
}
Second. Use Mockito.spy() in your test:
class EmpServiceTest {
#Test
void findSalary() {
TaxReturn taxReturn = Mockito.mock(TaxReturn.class);
// this is the main idea, here you using partial EmpService mock instance
// part is mocked(createClient()) and other part(findSalary()) is tested
EmpService service = Mockito.spy(EmpService.class);
when(service.createClient(any())).thenReturn(taxReturn);
when(taxReturn.apply(any(TaxReturnRequest.class))).thenReturn(taxReturn);
int yourExpectedValue = 5;
when(taxReturn.returnInRupee()).thenReturn(yourExpectedValue);
assertEquals(yourExpectedValue, service.findSalary(0));
}
}
Keep in mind that any(), spy(), when() and mock() methods are part of Mockito API. So there is nothing hidden here

ActiveWeb: mocking injected service

When mocking a service injected into a controller, a service method should return a mocked object, something like that:
public class EmptyInterventionServiceMock implements InterventionService {
#Override
public Intervention findByInvoiceNumber(String invoiceNumber, String language) {
return mockedIntervention(invoiceNumber, language);
}
protected Intervention mockedIntervention(String invoiceNumber, String language) {
return mock(Intervention.class);
}
}
Is it possible to mock some values to be return by the above mocked object (Intervention) to test fi they should be present in the generated JSON template ?
For example, depending on if Intervention has spare parts, services, states (all of them are just collections of other objects), etc. If so, JSON should contain the corresponding keys: services: [{....}], states: [{}], etc.
It would be nice to get the mocked object in the test and stub its return values. The only way I see to achieve that for the moment is to create a separate Mock service class and inject it in a test class as follows:
public class InterventionsControllerSpec extends ControllerSpec {
#Before
public void before() {
Injector injector = injector().bind(InterventionService.class).to(BaseInterventionServiceMock.class).create();
}
Where BaseInterventionServiceMock just extends EmptyInterventionServiceMock and stubs some methods return values by overriding its mockedIntervention method:
public class BaseInterventionServiceMock extends EmptyInterventionServiceMock {
#Override
protected Intervention mockedIntervention(String invoiceNumber, String language) {
Intervention intervention = mock(Intervention.class);
when(intervention.getString("ITV_DOCUMENT_NUMBER")).thenReturn("123");
when(intervention.getString("ITV_INVOICE")).thenReturn(invoiceNumber);
...
etc.
As it is far from ideal, I wonder if there is a DRYer way to do that ?
Thank you.
You are not missing anything. Your assumptions are correct. Creating a mock subclass of a service is how we do the testing. If you want a more elegant way, you can submit a proposal for consideration: https://github.com/javalite/activeweb/issues for consideration.

Mockito Method calls

I have a DAO implementation class :
public class DataPollingDAOImpl implements DataPollingDAO {
public List<String> getInfo(String id,String columnName)
{
// some code which calls the database and retrieves data.
}
}
I have written a mockito test case as follows-
public class connection{
#Mock private DataPollingDAOImpl myDao;
#Test public void test() {
when(myDao.getInfo("520", "Hole"));
}
}
I created a mock database connection as well. However what shall I do to print success on the console to show a success case after calling myDao.getInfo() in test method?
If you are mocking using #Mock then I suppose you want your mock to return a value, you specify how to return the value by:
when(myDao.getInfo(anyString(), anyString()).thenReturn(Arrays.asList("yourReturnValue"));
If you want to see if you have called your Mock, then normally #Spy is used and you write:
Mockito.verify(myDao).getInfo(anyString(),anyString());
And I do recommend you to use interfaces (as DataPollingDAO) and not implementations (DataPollingDAOImpl)

Is it possible to call default implementations of interfaces with Mockito's doCallRealMethod?

Suppose I have the following interface:
public interface ISomething {
default int doStuff() {
return 2 * getValue();
}
int getValue();
}
When I now mock this interface like this:
#Mock
private ISomething _something;
#Before
public void setup() {
doCallRealMethod().when(_something).doStuff();
}
and try to test the doStuff() method like the following:
#Test
public void testDoStuff() {
when(_something.getValue()).thenReturn(42);
assertThat("doStuff() returns 84", _something.doStuff(), is(84));
}
I expect the test to succeed, but I get:
org.mockito.exceptions.base.MockitoException:
Cannot call real method on java interface. Interface does not have any implementation!
Calling real methods is only possible when mocking concrete classes.
I tried subclassing ISomething with an abstract class like this:
public abstract class Something implements ISomething {
}
and mock this class like above. With this approach, I get the same.
Does Mockito not support calling default implementations?
That's correct. The current version of Mockito doesn't support this. You could raise a feature request here. Do note that it seems to be related to issue 456 which was fixed in release 1.10.0, so please make sure you test this in the latest version first.
I was working on a project using Mockito 1.9.5 and ran into the same issue that you found. We couldn't upgrade Mockito because of the way our build server worked. The problem we ran into was when we were writing unit tests for the concrete subclasses, as we couldn't stub out or include the default methods from the interface in our mock objects (so slightly different from your example).
Here is an example subclass using your model:
public class ConcreteSomething implements ISomething {
#Override
int getValue()
{
return 42;
}
}
Then in the unit test class, we explicitly made a private inner class. This class overrode all the default methods of the concrete class under test (i.e. ConcreteSomething) with the interface's default implementation. So in this example, something like:
private class ConcreteSomethingDefaultImpl extends ConcreteSomething {
#Override
int doStuff() {
return super.doStuff();
}
}
For us, a mock made using mock(ConcreteSomething.class) couldn't have it's default methods called using doCallRealMethod(), but mock(ConcreteSomethingDefaultImpl.class) could, and more importantly, it was the default implementation code in the interface that was being used.
I hope that helps anyone else who is constrained to use a particular version of Mockito.

Resources