How to mock methods with void return type?
I implemented an observer pattern but I can't mock it with Mockito because I don't know how.
And I tried to find an example on the Internet but didn't succeed.
My class looks like this:
public class World {
List<Listener> listeners;
void addListener(Listener item) {
listeners.add(item);
}
void doAction(Action goal,Object obj) {
setState("i received");
goal.doAction(obj);
setState("i finished");
}
private string state;
//setter getter state
}
public class WorldTest implements Listener {
#Test public void word{
World w= mock(World.class);
w.addListener(this);
...
...
}
}
interface Listener {
void doAction();
}
The system is not triggered with mock.
I want to show the above-mentioned system state. And make assertions according to them.
Take a look at the Mockito API docs. As the linked document mentions (Point # 12) you can use any of the doThrow(),doAnswer(),doNothing(),doReturn() family of methods from Mockito framework to mock void methods.
For example,
Mockito.doThrow(new Exception()).when(instance).methodName();
or if you want to combine it with follow-up behavior,
Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();
Presuming that you are looking at mocking the setter setState(String s) in the class World below is the code uses doAnswer method to mock the setState.
World mockWorld = mock(World.class);
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
System.out.println("called with arguments: " + Arrays.toString(args));
return null;
}
}).when(mockWorld).setState(anyString());
I think I've found a simpler answer to that question, to call the real method for just one method (even if it has a void return) you can do this:
Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();
Or, you could call the real method for all methods of that class, doing this:
<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);
Adding to what #sateesh said, when you just want to mock a void method in order to prevent the test from calling it, you could use a Spy this way:
World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();
When you want to run your test, make sure you call the method in test on the spy object and not on the world object. For example:
assertEquals(0, spy.methodToTestThatShouldReturnZero());
The solution of so-called problem is to use a spy Mockito.spy(...) instead of a mock Mockito.mock(..).
Spy enables us to partial mocking. Mockito is good at this matter. Because you have class which is not complete, in this way you mock some required place in this class.
First of all: you should always import mockito static, this way the code will be much more readable (and intuitive):
import static org.mockito.Mockito.*;
For partial mocking and still keeping original functionality on the rest mockito offers "Spy".
You can use it as follows:
private World world = spy(new World());
To eliminate a method from being executed you could use something like this:
doNothing().when(someObject).someMethod(anyObject());
to give some custom behaviour to a method use "when" with an "thenReturn":
doReturn("something").when(this.world).someMethod(anyObject());
For more examples please find the excellent mockito samples in the doc.
How to mock void methods with mockito - there are two options:
doAnswer - If we want our mocked void method to do something (mock the behavior despite being void).
doThrow - Then there is Mockito.doThrow() if you want to throw an exception from the mocked void method.
Following is an example of how to use it (not an ideal usecase but just wanted to illustrate the basic usage).
#Test
public void testUpdate() {
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {
Customer customer = (Customer) arguments[0];
String email = (String) arguments[1];
customer.setEmail(email);
}
return null;
}
}).when(daoMock).updateEmail(any(Customer.class), any(String.class));
// calling the method under test
Customer customer = service.changeEmail("old#test.com", "new#test.com");
//some asserts
assertThat(customer, is(notNullValue()));
assertThat(customer.getEmail(), is(equalTo("new#test.com")));
}
#Test(expected = RuntimeException.class)
public void testUpdate_throwsException() {
doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));
// calling the method under test
Customer customer = service.changeEmail("old#test.com", "new#test.com");
}
}
You could find more details on how to mock and test void methods with Mockito in my post How to mock with Mockito (A comprehensive guide with examples)
In Java 8 this can be made a little cleaner, assuming you have a static import for org.mockito.Mockito.doAnswer:
doAnswer(i -> {
// Do stuff with i.getArguments() here
return null;
}).when(*mock*).*method*(*methodArguments*);
The return null; is important and without it the compile will fail with some fairly obscure errors as it won't be able to find a suitable override for doAnswer.
For example an ExecutorService that just immediately executes any Runnable passed to execute() could be implemented using:
doAnswer(i -> {
((Runnable) i.getArguments()[0]).run();
return null;
}).when(executor).execute(any());
Adding another answer to the bunch (no pun intended)...
You do need to call the doAnswer method if you can't\don't want to use spy's. However, you don't necessarily need to roll your own Answer. There are several default implementations. Notably, CallsRealMethods.
In practice, it looks something like this:
doAnswer(new CallsRealMethods()).when(mock)
.voidMethod(any(SomeParamClass.class));
Or:
doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock)
.voidMethod(any(SomeParamClass.class));
I think your problems are due to your test structure. I've found it difficult to mix mocking with the traditional method of implementing interfaces in the test class (as you've done here).
If you implement the listener as a Mock you can then verify the interaction.
Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();
This should satisfy you that the 'World' is doing the right thing.
If you need to do some operations in the mocked void method, and you need to manipulate the argument that sent to void method; you can combine Mockito.doAnswer with ArgumentCaptor.capture method.
Let's say you have SpaceService that autowires a GalaxyService, which has a void method called someServiceMethod.
You want to write test for one of your method in SpaceService that calls GalaxyService's void method. Your planet is also generated inside SpaceService. So you don't have any chance to mock that.
Here is your sample SpaceService class that you want to write tests for.
class SpaceService {
#Autowired
private GalaxyService galaxyService;
public Date someCoolSpaceServiceMethod() {
// does something
Planet planet = new World();
galaxyService.someServiceMethod(planet); //Planet updated in this method.
return planet.getCurrentTime();
}
}
The GalaxyService.someServiceMethod method expects a planet argument. Does some stuff in the method. See :
GalaxyService {
public void someServiceMethod(Planet planet) {
//do fancy stuff here. about solar system etc.
planet.setTime(someCalculatedTime); // the thing that we want to test.
// some more stuff.
}
}
And you want to test this feature.
Here is an example :
ArgumentCaptor<World> worldCaptor = ArgumentCaptor.forClass(World.class);
Date testDate = new Date();
Mockito.doAnswer(mocked-> {
World capturedWorld = worldCaptor.getValue();
world.updateTime(testDate);
return null;
}).when(galaxyService.someServiceMethod(worldCaptor.capture());
Date result = spaceService.someCoolSpaceServiceMethod();
assertEquals(result, testDate);
In your example you should mock Listener item and use Mockito.verify to check interactions with it
Related
I have a code that I cannot correctly cover with tests.
I am using the Mockito library.
And I had difficulty at the moment of starting the test.
Below is the test code:
#Test
public void testLoadCar() {
when(remoteService.loadData()).thenReturn(new DataResult<DataCar>("", "", new DataCar()));
when(dataResult.hasError()).thenReturn(true);
when(dataResult.response.hasHeaders()).thenReturn(true);
requestNetwork = new RequestNetwork(remoteService);
Response<DataCar> response = requestNetwork.load(request);
}
These are objects in the test class: remoteService, dataResult, request.
I am concerned about the moment where I am trying to implement the when method:
when(dataResult.response.hasHeaders()).thenReturn(true);
I would like to know if such a recording will work.
If it doesn't work, then how can we handle this moment:
protected Response createResponse(DataResult<T> dataResult) {
if (dataResult.hasError() || !dataResult.response.hasHeaders()) {
return dataResult.getErrorMessage());
} else {
return Response.data(dataResult.value);
}
}
This is a method on the system under test (SUT) that has a createResponse() method. This method contains a call to the mock method of the DataResult object.
To implement dataResult.hasError () I got it:
when (dataResult.hasError ()). thenReturn (true);
Then with! DataResult.response.hasHeaders () I have a problem. Since I don't understand how to substitute the value I need.
Not all objects that your object under test interacts with need to be mocks.
Remember that you can use POJOs as well.
DataResult looks like a perfect candidate for a POJO.
You gain nothing by using a mock objet if you can create a POJO with desired state and behaviour.
Looking at the posted code, it looks like it is easy to create:
new DataResult<DataCar>("", "", new DataCar())
On top of that:
Your code looks suspicious to me.
when stubbing remoteService.loadData() you create a new instance of DataResult
subsequently, you stub some calls on dataResult, which is not an object returned from remoteService.loadData()
And to answer original post:
You can set fields on mocks (directly if access modifiers allow it, or via reflection otherwise). Note that this is highly not-idiomatic and surprising use of mocks.
class A {
B b;
}
class B {
boolean hasHeaders() {
return true;
}
}
#ExtendWith(MockitoExtension.class)
public class AAATest {
#Mock
A aMock;
#Mock
B bMock;
#BeforeEach
void setupMocks() {
aMock.b = bMock;
}
#Test
void testFieldInMockIsInitialized() {
Assertions.assertEquals(bMock, aMock.b);
}
}
I have a JUnit test as:
#Spy
ParallelSender parallelSender = new ParallelSender();
#Test
public void send() {
// making some data...
parallelSender.send(someData);
// check that internal method has been called with Sender Task made from someData
verify(parallelSender).doSend(any(SenderTask.class));
}
I however like to examine that SenderTask contains all the fields exactly as I need them. Can I tell the spy to intercept the doSend call, store its parameters in some array and then continue to real method?
Use the ArgumentCaptor:
#Test
public void send() {
// making some data...
parallelSender.send(someData);
// Define the captor for class
ArgumentCaptor<SenderTask> captor =
ArgumentCaptor.forClass(SenderTask.class);
// Capture input while verifying
verify(parallelSender).doSend(captor.capture());
// Assert
SomeTask result = captor.getValue();
// assertions on result
}
You can use an ArgumentCaptor.
#Captor
ArgumentCaptor<SenderTask> captor;
// or ArgumentCaptor<SenderTask> captor =
// ArgumentCaptor.forClass(SenderTask.class);
#Test public void send() {
// ...
verify(parallelSender).doSend(captor.capture());
SenderTask captured = captor.getValue();
I rarely use argument captor because it's usually not necessary.
Just do this
#Test
public void send() {
//given
SomeData myInput = ...
SenderTask expectedOutput = new SenderTask();
expectedOutput.setSomeField(/*expected field value*/);
//when
parallelSender.send(myInput);
//then
verify(parallelSender).doSend(expectedOutput);
}
The idea behind is to check that "doSend" was called with an expected object.
Note: just make sure that you implemented equals/hash method in SenderTask - or it will not work
Note2: I would suggest avoiding using any() in your unit tests. Usually when your are unit-testing something - you want to be as much precise as possible. So use concrete objects during results verification.
Hopefully it helps
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
I am new to writing tests in java, and seem to be unable to test if a method of a class is called.
I am sending metrics to datadog, and want to test in the code if a function of another class was called.
It says I need to mock first, but I couldn't get it to work.
MetricRecorder.java
import com.timgroup.statsd.StatsDClient;
import com.timgroup.statsd.NonBlockingStatsDClient;
import com.google.common.base.Preconditions;
public class MetricRecorder {
private final String namespace;
private final static StatsDClient metrics = new NonBlockingStatsDClient(
"my.prefix",
"localhost",
8125,
new String[] {"tag:value"}
);
public MetricRecorder(String namespace) {
Preconditions.checkNotNull(namespace);
this.namespace = namespace;
}
public void inc(String metricName) {
this.inc(metricName, 1);
}
public void inc(final String metricName, final long value) {
Preconditions.checkNotNull(metricName);
try {
metrics.recordHistogramValue(MetricRecorder.name(namespace, metricName), value);
} catch (Exception e) {
logger.warn("Unable to record metric {} due to :", metricName, e);
}
}
...
}
MetricRecorderTest.java
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
MetricRecorder recorder = new MetricRecorder("dev");
recorder.inc("foo", 1);
verify(recorder.metrics, times(1)).recordHistogramValue(eq("dev.foo"), 1);
}
}
When I run the test I get this => org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type NonBlockingStatsDClient and is not a mock!
Any idea of how I should be testing if recordHistogramValue was called, and if so with what arguments?
Since it looks like StatsDClient is an interface of some kind, it would make your testing effort easier to simply inject this dependency into your object. Even if you're not using an IoC container like Spring or Guice, you can still somewhat control this simply by passing an instance of it in through the constructor.
public MetricRecorder(String namespace, StatsDClient client) {
Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(client);
this.namespace = namespace;
this.client = client;
}
This will make your testing simpler since all you realistically need to do is mock the object passed in during test.
Right now, the reason it's failing is because you're newing up the instance, and Mockito (in this current configuration) isn't equipped to mock the newed instance. In all honesty, this set up will make testing simpler to conduct, and you should only need your client configured in one area.
#RunWith(MockitoJUnitRunner.class)
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
StatsDClient dClientMock = Mockito.mock(StatsDClient.class);
MetricRecorder recorder = new MetricRecorder("dev", dClientMock);
recorder.inc("foo", 1);
verify(recorder.metrics).recordHistogramValue(eq("dev.foo"), 1);
}
}
You are getting things wrong here. You don't use a mocking framework to test your "class under test".
You use the mocking framework to create mocked objects; which you then pass to your "class under test" within a test case. Then your "code under test" calls methods on the mocked object; and by controlling returned values (or by verifying what happens to your mock); that is how you write your testcases.
So, your testcase for a MetricRecorder doesn't mock a MetricRecorder; it should mock the StatsDClient class; and as Makoto suggests; use dependency injection to put an object of that class into MetricRecorder.
Besides: basically writing "test-able" code is something that needs to be practiced. I wholeheartedly recommend you to watch these videos if you are serious about getting in this business. All of them; really (worth each second!).
For public method calls, EasyMock's capture() allows you to intercept & examine arguments passed to the method. For private method calls, PowerMock's expectPrivate lets you mock private method calls.
Is there a way to somehow combine these and get the arguments passed to a private method call? Example:
public class Program
{
public FancyReturnType PublicMethod()
{
ArbitraryType localInstance = new ArbitraryType();
localInstance.setFoo(somePrivateHelperMethod());
localInstance.setBar(increasinglyComplexMagic());
long aLongValue = 11235L;
// more variables, more work
SomeType worker = privateHelperToIntercept(localInstance, aLongValue, otherVariables);
if (worker.something)
{
return retVal.aFancyReturnType;
}
else
{
return retVal.anotherFancyReturnType;
}
}
}
In this case, I want to examine the localInstance object as it is consumed by the privateHelperToIntercept() call.
I've found plenty of examples to mock private method calls; PowerMock's expectPrivate(partiallyMockedObject, "nameOfPrivateMethod", arg1, arg2) works great. I've also found examples to intercept arguments passed to public method calls; Capture<Type> myTestCapture = new Capture<Type>() combined with someMockedObject.PublicMethod(capture(myTestCapture)).
Unfortunately, I can neither get the two to work together, nor find examples of combining them. Has anyone seen a way to do this?
FWIW, I suspect Mockito can do this, but it's not included in our source/build/test system. I'd like to avoid the process of supporting new libraries in our system if possible.
If you are asking how to get a reference to localInstance, then the following code should suffice.
#PrepareForTest(Program.class)
public class Test {
#Test
public void testMethod() {
ArbitraryType passedLocalInstance = new ArbitraryType();
PowerMock.expectNew(ArbitraryType.class).andReturn(passedLocalInstance );
//remainder of the test method
assertEquals(14.2, passedLocalInstance .getValue());
}
}
Since java is pass-by-reference, the passedLocalInstance will be the argument passed into the method call. Did that answer your question?
new of any type is simply a static method. Deal with it in the same way... wrap it in a method, stub out the method. In this case you want to return a mock in your test, and then you can test all the interactions with that object (and remove dependency in your test on the code within the object you are creating which should have it's own tests)
public Program {
// your above code up to object creation
ArbitraryType localInstance = createArbitraryType();
// rest of your above code here
ArbitraryType createArbitraryType() {
return new ArbitraryType();
}
}
in your test...
public class MyTest {
TestableProgram extends Program {
#Override
ArbitraryType createArbitraryType() {
return this.arbitraryTypeMock;
}
}
private ArbitraryType arbitraryTypeMock;
private TestableMyClass objectToTest = new TestableProgram();
// rest of your tests...
}
Given your constraint's that's how I'd do it.
If could bend your constraints a bit I'd loosen up on the private methods, I've generally done away with private in favor of package default to make testing easier. If the folks IN your package are misbehaving, it's usually your code so private is mostly protecting you from yourself anyway. (but I know that isn't a valid answer your question as posed... ).