Reuse static method for Function mapping - java

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.

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

How to avoid repeating complex exception handling code in a wrapper class?

I have this class that wraps an object:
public class MyWrapper implements MyInterface {
private MyInterface wrappedObj;
public MyWrapper(MyInterface obj) {
this.wrappedObj = obj;
}
#Override
public String ping(String s) {
return wrappedObj.ping(s);
}
#Override
public String doSomething(int i, String s) {
return wrappedObj.doSomething(i, s);
}
// many more methods ...
}
Now I want to add complex exception handling around the wrappedObj call.
It is the same for all the methods.
How do I avoid repeating the same exception handling code over and over?
If your exception handling is fully generic you could implement the wrapper as InvocationHandler:
public class ExceptionHandler implements java.lang.reflect.InvocationHandler {
public ExceptionHandler(Object impl) {
impl_ = impl;
}
#Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return method.invoke(impl_, args);
}
catch (Exception e) {
// do exception handling magic and return something useful
return ...;
}
}
private Object impl_;
}
and then wrap it around an instance as follows:
MyInterface instance = ...
MyInterface wrapper = (MyInterface)java.lang.reflect.Proxy.newProxyInstance(
instance.getClass().getClassLoader(),
new Class[] { MyInterface.class },
new ExceptionHandler(instance));
wrapper.ping("hello");
If you want to avoid the cost of reflection, than just use a router function.
#Override
public String ping(String s) {
return (String) call("ping");
}
private Object call(String func) {
try {
switch(func) {
case "ping": return wrappedObj.ping(s);
// ... rest of functions ... //
}
} catch(Exception e) {
log(e);
}
}
The compiler can than effectively just jump to the function without pulling up Object specs or handlers. (A smart enough compiler may even just compile this to identical execution code as your current code, especially if you can cut the cast by always returning the same kind of object)
If you don't care about the thread and just want a default exception handler...
For the whole Java Runtime, call Thread.setDefaultUncaughtExceptionHandler
For a ThreadGroup, override ThreadGroup.uncaughtException
For a single Thread, call Thread.setUncaughtExceptionHandler
The advantage to a default handler, is that you can then add specific error handlers where needed, but the down side is you do lose the executing thread on error.

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