How to Stop static initialization with PowerMockito - mockito

I am working on an API for work, we use a shared library for multiple projects for the purposing of our logging framework. The class used uses all static methods for its calls.
I am trying to Unit test an API call, I can not have it call anything on the Logging class, else it will fail.
I have tried using Powermock, but it fails on
PowerMockito.mockStatic(LoggingFramework.class);
Mockito.when(LoggingFramework.startACall(anyString())).thenReturn("someTimestamp");
returning a
ClassCastException: org.apache.logging.slf4j.SLF4JLoggerContext cannot be cast to org.apache.logging.log4j.core.LoggerContext
the line in LoggingFramework that throws it, is inside a static initializer block outside of any methods in the class.

In order to suppress static initialization you should use #SuppressStaticInitializationFor. So your code will look like this:
#RunWith(PowerMockRunner.class)
#SuppressStaticInitializationFor("so.LoggingFramework") //here goes fully-qualified name of a class
public class LoggingFrameworkTest {
#Test
public void test() {
//given:
PowerMockito.mockStatic(LoggingFramework.class);
Mockito.when(LoggingFramework.foo(anyString())).thenReturn("stub");
//when:
String foo = LoggingFramework.foo("ignored");
//then:
PowerMockito.verifyStatic(LoggingFramework.class, Mockito.times(1));
LoggingFramework.foo(anyString()); //two-step verification of a static method
assertThat(foo, equalTo("stub"));
}
}
Verification of a static method is performed in two steps. It is explained here

Related

Mocking static class in Mockito

I have something like the following:
public class Foo {
public static String getValue(String key) {
return key + "_" + System.currentTimeMillis();
}
}
Now I need to have a test case for it and here is how I attempted:
#Test
public void testFoo() {
PowerMockito.mockStatic(Foo.class);
PowerMockito.when(Foo.getValue("123")).thenReturn("abcd");
PowerMockito.verifyStatic();
}
When I run the test case, I get this:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
at org.powermock.api.mockito.PowerMockito.when(PowerMockito.java:495)
Am I doing anything wrong?
Please advise.
Can you confirm that you've added a #PrepareForTest(Foo.class) annotation onto your test class as listed on the PowerMock site, and that you're using the PowerMockRunner JUnit4 runner?
Static methods are invoked with static dispatch, not dynamic dispatch using Java's normal polymorphism and method overrides. To replace the implementation, PowerMock needs to load a replacement class before the test starts running, and the runner and annotation make that happen.

How to mock Class object or how to mock private generic method

I have a private generic method below
private Section convertFromJsonToJavaObj(JSONObject jsonObj, Class<Section> classObj) throws SNPSysException {
// logic
return section;
}
how to mock above method
Testing private methods is generally a code smell. We generally only test public methods.
However if there is a quite complex logic in it and you really need to test it, you can remove the private modifier.
Section convertFromJsonToJavaObj(JSONObject jsonObj, Class<Section> classObj) throws SNPSysException {
// logic
return section;
}
This way your test will be able to access this method if it's in the same package (except that it should be in the test folder instead of main folder)

Is it possible to call default implementations of interfaces with Mockito's doCallRealMethod?

Suppose I have the following interface:
public interface ISomething {
default int doStuff() {
return 2 * getValue();
}
int getValue();
}
When I now mock this interface like this:
#Mock
private ISomething _something;
#Before
public void setup() {
doCallRealMethod().when(_something).doStuff();
}
and try to test the doStuff() method like the following:
#Test
public void testDoStuff() {
when(_something.getValue()).thenReturn(42);
assertThat("doStuff() returns 84", _something.doStuff(), is(84));
}
I expect the test to succeed, but I get:
org.mockito.exceptions.base.MockitoException:
Cannot call real method on java interface. Interface does not have any implementation!
Calling real methods is only possible when mocking concrete classes.
I tried subclassing ISomething with an abstract class like this:
public abstract class Something implements ISomething {
}
and mock this class like above. With this approach, I get the same.
Does Mockito not support calling default implementations?
That's correct. The current version of Mockito doesn't support this. You could raise a feature request here. Do note that it seems to be related to issue 456 which was fixed in release 1.10.0, so please make sure you test this in the latest version first.
I was working on a project using Mockito 1.9.5 and ran into the same issue that you found. We couldn't upgrade Mockito because of the way our build server worked. The problem we ran into was when we were writing unit tests for the concrete subclasses, as we couldn't stub out or include the default methods from the interface in our mock objects (so slightly different from your example).
Here is an example subclass using your model:
public class ConcreteSomething implements ISomething {
#Override
int getValue()
{
return 42;
}
}
Then in the unit test class, we explicitly made a private inner class. This class overrode all the default methods of the concrete class under test (i.e. ConcreteSomething) with the interface's default implementation. So in this example, something like:
private class ConcreteSomethingDefaultImpl extends ConcreteSomething {
#Override
int doStuff() {
return super.doStuff();
}
}
For us, a mock made using mock(ConcreteSomething.class) couldn't have it's default methods called using doCallRealMethod(), but mock(ConcreteSomethingDefaultImpl.class) could, and more importantly, it was the default implementation code in the interface that was being used.
I hope that helps anyone else who is constrained to use a particular version of Mockito.

Mockito implemetation for formhandlers in ATG

I am new to Mockito as a concept. Can you please help me understand using Mockito for formhandlers in ATG. Some examples will be appreciated.
There is a good answer (related to ATG) for other similar question: using-mockito-for-writing-atg-test-case. Please review if it includes what you need.
Many of ATG-specific components (and form handlers particularly) are known to be "less testable" (in comparison to components developed using TDD/BDD approach), b/c design of OOTB components (including reference application) doesn't always adhere to the principle of having "Low Coupling and High Cohesion"
But still the generic approach is applicable for writing unit-tests for all ATG components.
Below is a framework we've used for testing ATG FormHandlers with Mockito. Obviously you'll need to put in all the proper bits of the test but this should get you started.
public class AcmeFormHandlerTest {
#Spy #InjectMocks private AcmeFormHandler testObj;
#Mock private Validator<AcmeInterface> acmeValidatorMock;
#Mock private DynamoHttpServletRequest requestMock;
#Mock private DynamoHttpServletResponse responseMock;
private static final String ERROR1_KEY = "error1";
private static final String ERROR1_VALUE = "error1value";
#BeforeMethod(groups = { "unit" })
public void setUp() throws Exception {
testObj = new AcmeFormHandler();
initMocks(this);
}
//Test the happy path scenario
#Test(groups = { "unit" })
public void testWithValidData() throws Exception {
testObj.handleUpdate(requestMock, responseMock);
//Assume your formhandler calls a helper method, then ensure the helper method is called once. You verify the working of your helper method as you would do any Unit test
Mockito.verify(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
}
//Test a validation exception
#Test(groups = { "unit" })
public void testWithInvalidData() throws Exception {
Map<String, String> validationMessages = new HashMap<String, String>();
validationMessages.put(ERROR1_KEY, ERROR1_VALUE);
when(acmeValidatorMock.validate((AcmeInterface) Mockito.any())).thenReturn(validationMessages);
testObj.handleUpdate(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), ERROR1_VALUE);
}
//Test a runtime exception
#Test(groups = { "unit" })
public void testWithRunProcessException() throws Exception {
doThrow(new RunProcessException("")).when(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
testObj.handleAddGiftCardToCart(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), GENERAL_ERROR_KEY);
}
}
Obviously the above is just a framework that fit in nicely with the way in which we developed our FormHandlers. You can also add validation for redirects and stuff like that if you choose:
Mockito.verify(responseMock, Mockito.times(1)).sendLocalRedirect(SUCCESS_URL, requestMock);
Ultimately the caveats of testing other people's code still applies.
Here's what I do when I unit test a form handler (at least until I manage to release a major update for AtgDust). Note that I don't use wildcard imports, so I'm not sure if this causes any namespace conflicts.
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import org.junit.*;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import atg.servlet.*;
import some.form.handler.FormHandler;
#RunWith(JUnit4.class)
public class FormHandlerTest {
#Mock DynamoHttpServletRequest request;
#Mock DynamoHttpServletResponse response;
FormHandler handler;
#Before
public void setup() {
initMocks(this);
handler = new FormHandler();
}
#Test
public void testSubmitHandlerRedirects() {
handler.handleSubmit(request, response);
verify(response).sendLocalRedirect(eq("/success.jsp"), eq(request));
assertThat(handler.getFormError(), is(false));
}
}
The basic idea is to set up custom behavior for mocks/stubs using when() on the mock object method invocation to return some test value or throw an exception, then verify() mock objects were invoked an exact number of times (in the default case, once), and do any assertions on data that's been changed in the form handler. Essentially, you'll want to use when() to emulate any sort of method calls that need to return other mock objects. When do you need to do this? The easiest way to tell is when you get NPEs or other runtime exceptions due to working with nulls, zeros, empty strings, etc.
In an integration test, ideally, you'd be able to use a sort of in-between mock/test servlet that pretends to work like a full application server that performs minimal request/session/global scope management. This is a good use for Arquillian as far as I know, but I haven't gotten around to trying that out yet.

Can a mockito mock itself be wrapped at runtime?

If I wrap a mock created by Mockito at runtime and then call a method on the wrapper, the wrapped mock is not called. Please, see below:
This is the test I run:
import static org.mockito.Mockito.verify;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;
import org.junit.Test;
import org.mockito.Mockito;
public class MyTest {
#Test
public void mockIsCalled() {
final Bar bar = Mockito.mock(Bar.class);
final Bar wrapper = wrap(bar);
wrapper.foo();
verify(bar).foo();
}
#SuppressWarnings("unchecked")
private <T> T wrap(final T objToWrap) {
return (T) Enhancer.create(objToWrap.getClass(), NoOp.INSTANCE);
}
}
where Bar is:
public interface Bar {
String foo();
}
The test fails and the output I get is:
java.lang.NoSuchMethodError: java.lang.Object.foo()Ljava/lang/String;
at Bar$$EnhancerByMockitoWithCGLIB$$d2b59df8.foo(<generated>)
at MyTest.mockIsCalled(MyTest.java:18)
...
If I turn Bar into a class as in:
public class Bar {
public String foo() {
System.out.println("foo");
return null;
}
}
the test continues to fail, foo is printed on the console, and I get the output:
Wanted but not invoked:
bar.foo();
-> at MyTest.mockIsCalled(MyTest.java:20)
Actually, there were zero interactions with this mock.
at MyTest.mockIsCalled(MyTest.java:20)
...
I am confused.
The real problem that I am trying to solve is to wrap dynamic proxies (injected by Mule via component binding) in order to memoize the method calls on the wrapped dynamic proxies. I want to make it generic enough so that it is sufficient to wrap the dynamic proxy object without having to extend any interface.
Thanks
The problem you're seeing in the case of the Bar class, you would also be seeing in the interface version, if not for the cglib wackiness. You're not wrapping the mock, you're creating a new object. So, the original mock is never exercised.
For using the class version, have you tried the version of create() that accepts interfaces as params?
I'm not sure I fully grok your usage scenario, but for something Mockito-specific, you could try taking the proxy created by cglib and then using spy() on that instead of mocking a fresh object.
I don't know much about cglib, frankly, but perhaps you could implement your own Callback, which contains and delegates to the original object. You could supply that Callback to Enhancer.create() instead of the NoOp one.

Resources