Mockito: Can't mock method called on object - java

I'm not allowed to post real code, but this is basically what's going on:
We have a class InterfaceOneImpl that implements an interface InterfaceOne and a InterfaceTwoImpl that implements an InterfaceTwo
InterfaceTwoImpl gets instantiated in InterfaceOneImpl, and InterfaceTwoImpl.makeHttpRequest() gets called, but I need to mock this function in my unit tests because I obviously don't want to make http requests in them. makeHttpRequest is a public, non-static function that returns a String
My code does something like this:
public class InterfaceOneImpl implements InterfaceOne{
public String processRequest(...){
...
InterfaceTwo obj = new InterfaceTwoImpl();
obj.makeHttpRequest();
...
}
}
My test class looks like this:
public TestInterfaceOneImpl {
....
#Test
public void testProcessRequest(){
InterfaceOne interfaceOneImpl = new InterfaceOneImpl();
InterfaceTwo mock = PowerMockito.mock(InterfaceTwoImpl.class);
InterfaceTwo.when(mock.processRequest()).thenReturn("zzzz");
PowerMockito.whenNew(RiskValidationRestClientImpl.class).withNoArguments().thenReturn((RiskValidationRestClientImpl) mock);
String reqStr = interfaceOneImpl.processRequest();
//a bunch of failed assertions
}
}
My issue is that processRequest() is not being mocked properly, because the source code version of the method is actually being run rather than the mock. When I step through each line of my unit test in debug mode, I always end up in the body of the makeHttpRequest() function. What am I doing wrong?

My issue is that processRequest() is not being mocked properly, because the source code version of the method is actually being run rather than the mock. When I step through each line of my unit test in debug mode, I always end up in the body of the makeHttpRequest() function.
I think your question is wrong - processRequest, based on your example, is a method on InterfaceOne while mock is an instance of InterfaceTwo.
I assume you meant:
InterfaceTwo.when(mock.makeHttpRequest()).thenReturn("zzzz");
In any case ...
What am I doing wrong?
You think you're mocking something when you're not at all. Let's break down your example:
// First you create an instance of InterfaceOneImpl - OK
InterfaceOne interfaceOneImpl = new InterfaceOneImpl();
// Next you create a mock of InterfaceTwo (I think? I don't use PowerMock) - OK
InterfaceTwo mock = PowerMockito.mock(InterfaceTwoImpl.class);
// Then you tell the mock you created that it should return "zzzz" - OK
InterfaceTwo.when(mock.processRequest()).thenReturn("zzzz");
// Finally you call a method on your instance. YOU DO NOT USE "mock" in
// any way shape or form. As it's defined, "processRequest" creates a NEW
// instance of InterfaceTwo: InterfaceTwo obj = new InterfaceTwoImpl();
// and uses THAT instance. So of course you will always end up with the
// real method being called. You're creating a mock and literally never
// using it.
String reqStr = interfaceOneImpl.processRequest();
To fix: actually use your mock. Either by passing it in the function:
// Pass the object to use as an argument
public String processRequest(InterfaceTwo obj){
...
obj.makeHttpRequest();
...
}
// And then your test:
#Test
public void testProcessRequest() {
InterfaceOne interfaceOneImpl = new InterfaceOneImpl();
InterfaceTwo mock = PowerMockito.mock(InterfaceTwoImpl.class);
InterfaceTwo.when(mock.processRequest()).thenReturn("zzzz");
// NOW you can use the mock
String reqStr = interfaceOneImpl.processRequest(mock);
}
Or by passing it through to the class:
public class InterfaceOneImpl implements InterfaceOne {
public InterfaceOneImpl(InterfaceTwo obj) {
this.obj = obj;
}
public String processRequest(...){
...
obj.makeHttpRequest();
...
}
}
// And then your test
#Test
public void testProcessRequest(){
InterfaceTwo mock = PowerMockito.mock(InterfaceTwoImpl.class);
InterfaceTwo.when(mock.processRequest()).thenReturn("zzzz");
// Now interface one will use the mock to do the request
InterfaceOne interfaceOneImpl = new InterfaceOneImpl(mock);
String reqStr = interfaceOneImpl.processRequest();
//a bunch of failed assertions
}

Related

Is it possible to initialize some of the fields in a mock object

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

Skip execution of a line using Mockito

I am using mockito for unit testing and I want to skip a line.
// method I am testing
public String doSomeTask(String src, String dst) {
// some code
utils.createLink(src,dst);
// some more code
}
// utils class
public void createLink(String src, String dst) {
// do something
Path realSrc = "/tmp/" + src;
Files.createSymbolicLink(realSrc, dst);
// do something
}
// Test class
#Mock
private Utils utils;
#Test
public void testDoSomeTask() {
// this does not seem to work, it is still executing the createLink method
doNothing.when(utils).createLink(anyString(), anyString());
myClass.doSomeTask(anyString(), anyString());
}
Now, createLink is a void method and its failing during my testing with exception reason AccessDenied to create a directory.
I want to skip the line utils.createLink(src,dst); and continue with next lines. Is there a way I can tell Mockito to do this ?
Assuming that utils variable can be set with a setter, you can spy on your Utils class object and override its createLink() method.
The basic idea is:
Utils utils = new Utils();
Utils spyUtils = Mockito.spy(utils);
doNothing().when(spyUtils).createLink(any(String.class), any(String.class));
Now, set this spyUtils object via setter. Each time createLink is invoked, it does nothing.
You can either mock you utils method to do nothing (with PowerMockito) or change you code so utils method is not static and you can inject the mock instance of utils method to the object you test, something like this:
class ForTesting{
UtilsClass utilsInstance;
ForTesting (UtilsClass utilsInstance) {
this.utilsInstance = utilsInstance;
}
// method you test
public String doSomeTask(String src, String dst) {
// some code
utilsInstance.createLink(src, dst);
// some more code
}
}
#Test
public void test(){
UtilsClass utilsInstance = mock(UtilsClass.class);
ForTesting classForTesting = new ForTesting(utilsInstance);
assertEquals("yourValue",classForTesting.doSomeTask());
}
Mocking with PowerMockito gives some overhead, because you cant override static methods without inheritance, so some native methods needed to modify byte code at runtime.

Save information that was spied by Mockito

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

Mockito mocking a new instance call with parameters

For school purposes I am creating an application that's working with a stock API.
I am trying to write a test for a method that gets all the stock data of the last 10 years. Instead of actually getting all that data, I want to throw an exception.
The method I Want to test:
#Override
public List<StockData> getAllTeslaStockData() throws AlphaVantageException {
List<StockData> stockData;
AlphaVantageConnector apiConnector = new AlphaVantageConnector(APIKEY, TIMEOUT);
TimeSeries stockTimeSeries = new TimeSeries(apiConnector);
try {
Daily responseDaily = stockTimeSeries.daily("TSLA", OutputSize.FULL);
stockData = responseDaily.getStockData();
} catch (AlphaVantageException e) {
LOGGER.log(Level.SEVERE, "something went wrong: ", e);
throw e;
}
return stockData;
}
The stockTimeSeries.daily(....) call can throw the AlphaVantageException.
I've mocked the TimeSeries class like this:
TimeSeries stockTimeSeries = mock(TimeSeries.class);
In my test class I want to mock this call, and return an exception instead of actual data.
when(stockTimeSeries.daily("TSLA", OutputSize.FULL)).thenThrow(new AlphaVantageException("No stock data available"));
Regardless of how I am trying to mock this bit of code, it'll never throw the exception. It will always just execute the code, and return valid stock data, instead of throwing the exception like i've tried to do.
How can I mock this bit of code, so that itll throw the exception I am expecting for my tests.
The AlphaVantageConnector, TimeSeries and Daily classes are part of a library used to access the stock API, so I can't change these classes.
I am using JUnit 4.12 and Mockito to try and achieve this.
You can use thenThrow() method. Below is the example
#Test(expected = NullPointerException.class)
public void whenConfigNonVoidRetunMethodToThrowEx_thenExIsThrown() {
MyDictionary dictMock = mock(MyDictionary.class);
when(dictMock.getMeaning(anyString()))
.thenThrow(NullPointerException.class);
dictMock.getMeaning("word");
The TimeSeries object is created in the method itself, so you can't mock it - mocking is intended to mock members.
What you can do is to do something like
class YourClass {
private Supplier<TimeSeries> seriesCreator = () -> {
return new TimeSeries(new AlphaVantageConnector(APIKEY, TIMEOUT));
}
which you use to create the series in your method
#Override
public List<StockData> getAllTeslaStockData() throws AlphaVantageException {
TimeSeries stockTimeSeries = seriesCreator.get();
Now you can mock that Supplier.
#Mock Supplier<TimeSeries> seriesCreatorMock;
#InjectMocks MyClass sut;
and in your test
#Test(expected = AlphaVantageException.class)
void testException() {
when(seriesCreatorMock.get()).thenThrow(new AlphaVantageException());
sut.getAllTeslaStockData()
}
EDIT: as suggested by Angkur in the comments, the clean way would be to
class SeriesCreator implements Supplier<TimeSeries> {
public TimeSeries get() {
return new TimeSeries(new AlphaVantageConnector(APIKEY, TIMEOUT));
}
}
class YourClass {
private Supplier<TimeSeries> seriesCreator = new SeriesCreator();
// ...
The code in the main class is creating a new instance of TimeSeries which it will use every time this method is called, so the mocked TimeSeries object is not getting used at all.
TimeSeries stockTimeSeries = new TimeSeries(apiConnector); // --> This is not getting mocked
try {
Daily responseDaily = stockTimeSeries.daily("TSLA", OutputSize.FULL);
stockData = responseDaily.getStockData();
}
You should create another method in your class (or even a separate class if it better satisfies the SOLID principles) which returns you the TimeSeries object. Something like:-
<access modifier> TimeSeries getTimeSeries(...) {
}
and then this method should be mocked in the Junit, and when mocked, it should return the Mocked TimeSeries reference (which is created in TimeSeries stockTimeSeries = mock(TimeSeries.class); ). You would need to use .spy() on the main class (unless you are using a different class to create TimeSeries object) in order to be able to mock the specific method getTimeSeries() but not the others.
MainClass mainObject = Mockito.spy(new MainClass());
Mockito.when(mainObject.getTimeSeries()).thenReturn(stockTimeSeries);
Then, the method call stockTimeSeries.daily() will get actually mocked by your existing code :
when(stockTimeSeries.daily("TSLA", OutputSize.FULL)).thenThrow(new AlphaVantageException("No stock data available"));
NOTE: you should also consider using .anyString() style methods provided by Mockito API while mocking.

How to mock a method call inside a method for a JUnit test?

I have a class that I am trying to write unit tests for (I didn't create the class) and I'm not sure how to just test one method.
The class (ShapeUtility in this example) class looks something like this:
public ShapeUtility(ShapeConfig config) {
this.config = config;
}
public CircleDetails getDetails() {
CircleDetails cDetails = new CircleDetails();
//stuff
cDetails = getSize();
//stuff
return cDetails;
}
public CircleDetails getSize() {
CircleDetails cDetails = new CircleDetails();
//stuff
cDetails.setSize(size);
//stuff
return cDetails;
}
I looked around on the web and was using this as an example to mock it: https://www.stevenschwenke.de/spyingWithMockito
What I want to do for the JUnit is something like this (so the method getSize doesn't actually get called within the getDetails method):
ShapeConfig config = new ShapeConfig();
ShapeUtility utility = new ShapeUtility(config);
CircleDetails cDetails = spy(new CircleDetails());
when(cDetails.getSize().thenReturn(5));
utility.getDetails();
However, the cDetails doesn't get passed in to the ShapeUtility methods so this doesn't work. Is there another way to do this? Or should I just look into rewriting the code so that a CircleDetails object gets passed in to the ShapeUtility methods?
I believe you want to test one method while, mocking other one within the same class, that is why you trying to use partial mocks. Here is what I suggest for your case:
ShapeConfig config = mock(new ShapeConfig());
CircleDetails cDetails = mock(new CircleDetails());
ShapeUtility utility = new ShapeUtility(config);
// here is our spy
ShapeUtility spyUtility = spy(utility);
// here I assume that you have two getSize() methods, first in CircleDetails which returns number
// and second in ShapeUtility, which returns CircleDetails
when(cDetails.getSize().thenReturn(5));
when(spyUtility.getSize().thenReturn(cDetails));
// and then your assertion code
// assertThat(spyUtility.getDetails()...
Hope it will help.

Categories