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
}};
}
Related
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.
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 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.
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
Using Play, the controller class has several methods with the pattern:
public static Promise<Result> getFoo() {
Promise<Response> resp = WS.url("/api/foo").get();
return resp.map(new Function<Response, Result>() {
#Override
public Result apply(Response arg0) throws Throwable {
String body = arg0.getBody();
return Results.ok(body);
}
});
}
I considered creating seperate mapping function:
private static Function<Response, Result> mapResponse = new Function<Response, Result>() {
#Override
public Result apply(Response arg0) throws Throwable {
String body = arg0.getBody();
return Results.ok(body);
}
};
So that I can then reuse this in multiple static methods:
public static Promise<Result> getFoo() {
Promise<Response> resp = WS.url("/api/foo").get();
return resp.map(mapResponse);
}
public static Promise<Result> getBar() {
Promise<Response> resp = WS.url("/api/bar").get();
return resp.map(mapResponse);
}
Intuitively I think this may cause problems as multiple methods will be reusing the same static mapping method, but I realized that I am not sure of the actual behavior. I am wondering if reusing a static variable could bottleneck concurrent calls, or the JVM will automatically instantiate multiple copies to handle processing in different methods.
What are the drawbacks of such an approach, or will it actually work properly? If not, what are my options to reduce the boilerplate mapping code used in multiple methods?
Note: I don't think the question above is actually specific to Play but is more of a generic Java coding question, hence not using Play as a tag.