How do I mock static method that calls other private static methods? - java

How can I mock this method below that calls another private static method?
public class testA {
public static JSONObject retrieveOrder(String orderId)
throws Exception {
String url = "/contract/";
JSONObject order = new JSONObject();
order.put("orderId", orderId);
return orderPOST(url, order);
}
private static orderPOST(String url, JSONObject order) {
return orderPOSTString(url, order.toString());
}
private static orderPOSTString (String url, String order) {
//do another call to method which will return JSONObject
}
}
How can I just mock retrieveOrder method only as I don't care any of those private methods? And as for those private static methods, I can't modify any of them so have to accept them as is.
This is my test:
#Test
public void testRetrieveOrderMethod() throws Exception {
String url = "/contract/";
JSONObject order = new JSONObject();
order.put("orderId", orderId);
PowerMockito.spy(testA.class);
PowerMockito.doReturn(url, order.toString()).when(testA.class, "orderPOST", Matchers.any(), Matchers.any());
JSONObject retrieved = testA.retrieveOrder("12345");
}
Please let me know if I miss anything here. I keep getting NullPointerException as I suspect it's actually calling those private methods.

In your code, when(testA.class, "orderPOST"... is mocking orderPost method.
If you want to mock just the retrieveOrder method and want to ignore the other ones, your test class should be:
#RunWith(PowerMockRunner.class) // needed for powermock to work
// class that has static method and will be mocked must be in PrepareForTest
#PrepareForTest({ testA.class })
public class MyTestClass {
#Test
public void testRetrieveOrderMethod() throws Exception {
// JSON object you want to return
JSONObject order = new JSONObject();
order.put("orderId", "whatever value you want to test");
PowerMockito.spy(testA.class);
// retrieveOrder will return order object
PowerMockito.doReturn(order).when(testA.class, "retrieveOrder", Mockito.anyString());
// call static method
JSONObject retrieved = testA.retrieveOrder("12345");
// do the assertions you need with retrieved
}
}
You could also change spy and doReturn to:
PowerMockito.mockStatic(testA.class);
Mockito.when(testA.retrieveOrder(Mockito.anyString())).thenReturn(order);
Both will work the same way.

Related

How to mock the static method with mockito to do unit test

I have a method like this.
public Response post(String json) {
EventList list = Recorder.getRecorders();
if (null == list || list.isEmpty()) {
throw new ServiceUnavailableException("An Recorder is either not configured");
}
String targetIUrl = list.getNext().getBase();
String targetV2Url = targetUrl + "/v2";
// other processes......
}
I want to mock Recorder.getRecorder() and do something like when(Recorder.getRecorder()).thenReturn(null) and test if throw a 503 exception. But getRecorder() is a static method. I know Mockito cannot mock the static method, but I still wanna know if it is possible to change some code made this testable without using Powermock or other libraries.
If I mock Recorder, do I have to change the method to post(String json, Recorder recorder)? Otherwise, how can I make this mock interact with the method?
If you want to mock the getRecorders() behaviour without using a library for mocking static methods (such as Powermock) then you'll have to extract the static call from inside post(). There are a few options for this:
Pass the EventList into post()
public post(String json, EventList list) {
...
}
Inject the EventList into the class which contains post()
public class TheOneThatContainsThePostMethod {
private EventList eventList;
public TheOneThatContainsThePostMethod(EventList eventList) {
this.eventList = eventList;
}
public post(String json) {
if (null == this.eventList || this.eventList.isEmpty()) {
throw new ServiceUnavailableException("An Recorder is either not configured");
}
}
}
Hide the static method call inside another class and inject an instance of that class into post() or the class which contains post(). For example:
public class RecorderFactory {
public EventList get() {
return Recorder.getRecorders();
}
}
public class TheOneThatContainsThePostMethod {
private RecorderFactory recorderFactory;
public TheOneThatContainsThePostMethod(RecorderFactory recorderFactory) {
this.recorderFactory = recorderFactory;
}
public post(String json) {
EventList list = recorderFactory.getRecorders();
...
}
}
// Or ...
public post(String json, RecorderFactory recorderFactory) {
EventList list = recorderFactory.getRecorders();
...
}
With the first two approaches your test can simply invoke post() providing (1) a null EventList; (2) an empty EventList ... thereby allowing you to test the 'throw a 503 exception' behaviour.
With the third approach you can use Mockito to mock the behaviour of the RecorderFactory to return (1) a null EventList; (2) an empty EventList ... thereby allowing you to test the 'throw a 503 exception' behaviour.

How to mock array of class using Mockito

I want to mock Order array class Order[].class. below mockMapper reads Order[].class and need to return Order[].class.
Service class
public class OrdersConnectorImpl {
public Order getOrderById(String Id, OrderType orderType) throws Exception {
Response response = null;
response = orderServiceTarget.queryParam("ID", Id).queryParam(ORDER_TYPE, orderType).request().accept(MediaType.APPLICATION_JSON)
.get();
final StatusType responseStatus = response.getStatusInfo();
final String serverResponseStr = response.readEntity(String.class);
if (responseStatus.equals(Response.Status.OK)) {
objectMapper = getObjectMapper(); // we have a private method in this class
Order[] orders = objectMapper.readValue(serverResponseStr, Order[].class);
if(orders.length>0) {
return orders[0];
}
}
}
}
Test class
public class OrdersConnectorImplTest {
private ObjectMapper mockMapper;
private class MockOrdersConnectorImpl extends OrdersConnectorImpl {
#Override
protected ObjectMapper getObjectMapper() {
return mockMapper;
}
}
}
#Test
public void test_getRenewalOrderForContract() throws Exception {
Response mockResponse = mock(javax.ws.rs.core.Response.class);
Order mockOrder = mock(Order.class);
when(mockResponse.getStatusInfo()).thenReturn(Status.OK);
when(mockResponse.readEntity(String.class)).thenReturn("{}");
when(mockBuilder.get()).thenReturn(mockResponse);
when(mockMapper.readValue("{}", Order[].class)).thenReturn(mockOrder); // this is the problem line
orderConnector.getOrderById("id", OrderType.NEW);
}
}
Please correct me here how to return expected.
You have autowired mockMapper which means, the actual object of ObjectMapper will be injected.
And in the when part, you setting up the behavior of mockMapper, which shouldn't be the case.
Edit 1
In your case, there is no need for mocking the Order class, you have to return the array Order which you can create in the tests.
For your information, with Junit there is no way, you can mock the object which is been created inside the method.

How to define and extends Expectations in JMockit?

I recently started using JMockit. So far it's very nice. But I find myself writing something like this over and over.
#Test
public void testFoo() {
new Expectations() {
x.foo(); result = "1"; // expectation common to all test cases
x.bar(); result = "2"; // varying expectation per each case
}
...
}
Is there a way to define a common Expectations class, but extends/override it from each test case?
Thanks for all your help!
I sometimes do things like:
protected void prepareHttpClientExpectations(#Mocked final Call call, #Mocked final Response response,
#Mocked final ResponseBody responseBody,
final String requestMethod, final boolean isSuccessfull,
final String body) throws IOException {
new Expectations() {{
OkHttpClient client = new OkHttpClient();
client.newCall(with(new Delegate<Request>() {
boolean delegate(Request request) {
assertHttpRequest(request, requestMethod);
return true;
}
}));
result = call;
call.execute();
result = response;
response.isSuccessful();
result = isSuccessfull;
response.body();
result = responseBody;
responseBody.string();
result = body;
}};
}
in order to reuse expectations. Then you just need to call the method with the desired values and ready to go ;)
You can create non-final expectations and extend them.
See the doc:
Rather than creating anonymous subclasses, we can also create named
subclasses to be reused in multiple tests. Some examples:
final expecation:
public final class MyReusableExpectations extends Expectations {
public MyReusableExpectations(...any parameters...) {
// expectations recorded here
}
}
non-final expecation(which can be extended as base class):
public class ReusableBaseExpectations extends Expectations {
protected ReusableBaseExpectations(...) {
// expectations here
}
}
test method:
#Test
public void someTest(#Mocked final SomeType aMock, etc.) {
// Record reusable expectations by instantiating a final "...Expectations" class.
new MyReusableExpectations(123, "test", etc.);
// Record and extend reusable expectations by instantiating a non-final base class.
new ReusableBaseExpectations() {{
// additional expectations
}};
}

Mockito mock a method but use its parameters for the mocked return

There is a method public Content createChild(String path, String contentType, Map<String,Object> properties) I'd like to mock.
I want to mock it that way that the method is called with any kind of arguments, therefore when() wouldn't work because I have to tell it what arguments the method should receive to be actually mocked.
So I want to actually react on any method call independent of its given arguments (use spies?) and then call some kind of "callback" to return a Content object which I want build together out of the real arguments given to the method.
I could not find a specific API in Mockito which supports this.
You can use Matchers:
You can try something like:
when(service.createChild(anyString(), anyString(), anyMap()))
.thenReturn(any(Content.class));
Sure you can. I have written simple unit test for this
public class MockitoTest {
private SampleService sampleService;
#Before
public void setUp() throws Exception {
sampleService = Mockito.mock(SampleService.class);
}
#Test
public void mockitoTest() throws Exception {
when(sampleService.createChild(anyString(), anyString(), anyMapOf(String.class, Object.class)))
.thenAnswer(invocationOnMock -> {
//Here you can build result based on params
String pathArg = (String) invocationOnMock.getArguments()[0];
if (pathArg.equals("p1")) {
return new Content("Content for p1");
} else if (pathArg.equals("p2")) {
return new Content("Content for p2");
} else {
return invocationOnMock.callRealMethod();
}
});
Content content = sampleService.createChild("p1", "any", new HashMap<>());
assertEquals("Content for p1", content.getData());
content = sampleService.createChild("p2", "any", new HashMap<>());
assertEquals("Content for p2", content.getData());
content = sampleService.createChild("whatever", "any", new HashMap<>());
assertEquals("original", content.getData());
}
/**
* Sample service with method
*/
private static class SampleService {
public Content createChild(String path, String contentType, Map<String, Object> properties) {
return new Content("original");
}
}
/**
* Content example
*/
private static class Content {
private String data;
Content(String data) {
this.data = data;
}
String getData() {
return data;
}
}
}
You can use matchers
MyClass m = mock(MyClass.class);
when(m.createChild(any(String.class), any(String.class), any(Map.class))).thenReturn(new Content());
You should also be able to use the parameters this way
when(m.createChild(any(String.class), any(String.class), any(Map.class))).thenAnswer(
new Answer<Content>()
{
#Override
public Content answer(final InvocationOnMock invocation) throws Throwable
{
return new Content((String) invocation.getArguments()[0],
(String) invocation.getArguments()[1],
(Map) invocation.getArguments()[2]);
}
}
}
);
You can try something like with use of eq() and any() as per as your requirement:
when(service.createChild(eq("helloe/hi"), any(String.class), any(Map.class)))
.thenReturn(any(Content.class));
eq - If we want to use a specific value for an argument, then we can use eq() method.
any - Sometimes we want to mock the behavior for any argument of the given type

Mockito mock all methods call and return

I have a problem when writing unit testing with mock. There is a object which I need to mock have a lot getter, which I do call them at the code. However, those are not the purpose of my unit test. So, is there is a way I can mock all the methods instead of mock them one by one.
Here is the code example:
public class ObjectNeedToMock{
private String field1;
...
private String field20;
private int theImportantInt;
public String getField1(){return this.field1;}
...
public String getField20(){return this.field20;}
public int getTheImportantInt(){return this.theImportantInt;}
}
and this is the service class I need to test
public class Service{
public void methodNeedToTest(ObjectNeedToMock objectNeedToMock){
String stringThatIdontCare1 = objectNeedToMock.getField1();
...
String stringThatIdontCare20 = objectNeedToMock.getField20();
// do something with the field1 to field20
int veryImportantInt = objectNeedToMock.getTheImportantInt();
// do something with the veryImportantInt
}
}
within the test class, the test method is like
#Test
public void testMethodNeedToTest() throws Exception {
ObjectNeedToMock o = mock(ObjectNeedToMock.class);
when(o.getField1()).thenReturn(anyString());
....
when(o.getField20()).thenReturn(anyString());
when(o.getTheImportantInt()).thenReturn("1"); //This "1" is the only thing I care
}
So, is there a way that I can avoid writing all the "when" for the useless "field1" to "field20"
You can control the default answers of your mock. When you're creating the mock, use:
Mockito.mock(ObjectNeedToMock.class, new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
/*
Put your default answer logic here.
It should be based on type of arguments you consume and the type of arguments you return.
i.e.
*/
if (String.class.equals(invocation.getMethod().getReturnType())) {
return "This is my default answer for all methods that returns string";
} else {
return RETURNS_DEFAULTS.answer(invocation);
}
}
}));
If you're not interested in the result of getField1() to getField20() in a particular test case, you shouldn't mock it at all. In other words, if all the specific test case should be concerned about is getTheImportantInt(), then your test case should look like this:
#Test
public void testMethodNeedToTest() throws Exception {
ObjectNeedToMock o = mock(ObjectNeedToMock.class);
when(o.getTheImportantInt()).thenReturn("1");
// test code goes here
}
For kotlin users:
val mocked:MyClassToMock = Mockito.mock(MyClassToMock::class.java,
object:Answer<Any> {
override fun answer(invocation: InvocationOnMock?): Any {
if (String::class.java.equals (invocation?.method?.getReturnType())) {
return "Default answer for all methods that returns string";
} else {
return Mockito.RETURNS_DEFAULTS.answer(invocation);
}
}
})

Categories