I'm trying to unit test code that uses com.basho.riak:riak-client:2.0.0. I mocked all riak client classes and was hoping to get a useless but working test. However, this fails with a null pointer:
java.lang.NullPointerException
at com.basho.riak.client.api.commands.kv.KvResponseBase.convertValues(KvResponseBase.java:243)
at com.basho.riak.client.api.commands.kv.KvResponseBase.getValue(KvResponseBase.java:150)
at com.basho.riak.client.api.commands.kv.FetchValue$Response.getValue(FetchValue.java:171)
My test looks like this:
#Test public void test() {
RiakClient riakClient = mock(RiakClient.class);
#SuppressWarnings("unchecked")
RiakCommand<FetchValue.Response, Location> riakCommand = (RiakCommand<FetchValue.Response, Location>) mock(RiakCommand.class);
Response response = mock(Response.class);
when(riakClient.execute(riakCommand)).thenReturn(response);
Response returnedResponse = riakClient.execute(riakCommand);
when(response.getValue(Object.class)).thenReturn(new Object());
MyPojo myData = returnedResponse.getValue(MyPojo.class);
// Make assertions
}
How do you unit test code that uses the riak client? Eventually I would like to ensure that the expected type/bucket/key combination is used and that the expected RiakCommand is run.
EDIT: I dug more into the FetchValue class and found this structure:
FetchValue
- is public final
FetchValue.Response
- is public static,
- has a package-private constructor Response(Init<?> builder)
FetchValue.Response.Init<T> is:
- protected static abstract class Init<T extends Init<T>> extends KvResponseBase.Init<T>
And there is FetchValue.Response.Builder:
static class Builder extends Init<Builder>
- with build() that: return new Response(this);
I assume that Mockito gets lost somewhere among the inner classes and my call ends up in KvResponseBase.convertValues, where the NP is thrown. KvResponseBase.convertValues assumes a List<RiakObject> of values and I see no sane way of assigning it.
I have investigate a bit your case. I have reduce your example to this simple SSCCE:
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import org.junit.Test;
import com.basho.riak.client.api.commands.kv.FetchValue.Response;
public class RiakTest {
#Test
public void test() throws Exception {
Response response = mock(Response.class);
given(response.getValue(Object.class)).willReturn(new Object());
}
}
which throws this error:
java.lang.NullPointerException
at com.basho.riak.client.api.commands.kv.KvResponseBase.convertValues(KvResponseBase.java:243)
at com.basho.riak.client.api.commands.kv.KvResponseBase.getValue(KvResponseBase.java:150)
at com.basho.riak.client.api.commands.kv.FetchValue$Response.getValue(FetchValue.java:171)
at RiakTest.test(RiakTest.java:12)
After some digging, i think i have identified the problem. It is that you are trying to stub a public method which is inherited from a package (visibility) class:
abstract class KvResponseBase {
public <T> T getValue(Class<T> clazz) {
}
}
It seems that Mockito fails to stub this method so the real one is invoked and a NullPointerException is thrown (due to an access of a null member: values).
One important thing to note is that if this function invocation not fails, Mockito would show a proper error:
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.
I guess it is a Mockito bug or limitation so i have open an issue in the Mockito tracker where i have reproduce your case with simple classes.
UPDATE
The issue i opened is in fact a duplicate of an existing one. This issue will not be fixed but a workaround exists. You may use the Bytebuddy mockmaker instead of the cglib one. Explanations could be found here.
You can not mock final classes and final and/or static methods with mockito. Note that static nested classes are fine. This is because mockito subclasses (I'm not 100% sure this is the exact operation, it uses CGLIB to generate classes) objects, but isn't allowed to override final methods or extend the final classes. For static methods no overriding is ever possible.
In your code you probably are trying to call a final class or method. It is hard to tell which class causes the problem, from your NullPointer stackstrace you should suspect the first object on it that you have mocked (going up starting from the testcase method). The method on the mock should not be calling any other methods (expect internal to mockito), so probably that is final, because you is does not seem to call a 'mocked' method.
In your case the stacktrace is not complete (as your testcase is not on it). In a quick look on the riak framework I couldn't find the method take a look at FetchValue$Response.getValue.
Also note the following. From the snippet you posted, I can not tell what you are testing in your testcase. All objects you create are mocks. Normally you have 1 (or a few) real classes that you are testing. The other classes (that interact with your classes under test) you mock, to be able to simulate complex behavior.
Follow up:
Thanks #gontard I was able to find this:
<dependency>
<!-- We need this fix: https://github.com/mockito/mockito/pull/171 to use mockito with Riak -->
<!--http://stackoverflow.com/questions/28442495/how-to-mock-riak-java-client#28474106-->
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.0.52-beta</version>
<scope>test</scope>
</dependency>
That has the fixes included.
Unfortunately, if you use both Fetch and MultiFetch (likely), you're up a creek.
MultiFetch.Response is a final class (so you can use mockito, you need to use PowerMock)
FetchValue.Response has the issues you outlined, and can only be fixed with the beta mockito, not available with powermock yet...
Update, I figured out how to use both mockito & powermock together (until powermock upgrades):
<!-- We need this to mock Multi-Fetch responses from Riak, which are final -->
<!-- However, we need the beta version of mockito due to bugs (see below),
so we _cannot_ use the mockito api provided by powermock, do _not_ include _powermock-api-mockito, it'll mess stuff up -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.4</version>
<scope>test</scope>
</dependency>
<!--If we don't include this, we get: -->
<!--java.lang.IllegalStateException:
Extension API internal error: org.powermock.api.extension.proxyframework.ProxyFrameworkImpl could not be located in classpath.-->
<!-- it looks like this is due to some discrepancy in packaging with mockito 2, this may be fixed in Fall 2016:
https://groups.google.com/forum/#!topic/powermock/cE4T40Xa_wc -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-easymock</artifactId>
<version>1.6.4</version>
</dependency>
<!-- We need this fix: https://github.com/mockito/mockito/pull/171 to use mockito with Riak -->
<!--http://stackoverflow.com/questions/28442495/how-to-mock-riak-java-client#28474106-->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.0.52-beta</version>
<scope>test</scope>
</dependency>
Related
I am trying to verify that a static method is called during the test. However, it throws an exception due to the fact that more than one static method of the same class is called during the run. Both these static methods are mocked. The exact exception is like this :-
An unexpected error occurred while verifying a static stub.
To correctly verify a stub, invoke a single static method of
com.booking.capacityservicejobs.models.YourStaticClass in the provided
lambda.
For example, if a method 'sample' was defined, provide a lambda or
anonymous class containing the code.
The code is something like this:-
try (MockedStatic<MyClass1> theMock = Mockito.mockStatic(MyClass1.class);
MockedStatic<MyClass2> configMock = Mockito.mockStatic(MyClass2.class);
MockedStatic<MyClass3> downtimeMock = Mockito.mockStatic(MyClass3.class)) {
theMock.when(MyClass1::lockAndFetch).thenReturn(duRuns);
theMock.when(() -> MyClass1.startAndUnlock(1)).thenAnswer(invocation -> null);
configMock.when(() -> MyClass2.getById(1)).thenReturn(dummyConfig);
downtimeMock.when(() -> MyClass3.isScheduledForRole("app-dummy")).thenReturn(false);
new RunExecutor().run(); //this executes the code to be tested
theMock.verify(() -> MyClass1.startAndUnlock(1));
}
Can I get around this limitation without using powermock? What is the correct way to verify multiple(different) static method calls?
Even if I agree is not a good practice, I have had to deal myself with this issue because I had a dependency with a static utilities class in a library that I could not refactor it, so here goes my answer.
My case it's not exactly as yours: I was testing a method HttpUtils.logProtocolMessages that inside made a call to 2 different static methods in LoggingApi utility class; both mehods returned void. This worked for me:
#Test
public void logProtocolMessageWithoutRequestTest() {
try (MockedStatic<LoggingApi> mockLog = Mockito.mockLog(LoggingApi.class)){
mockLog.when(() -> {
LoggingApi.setProtocolSendMessage(anyString(), anyString());
LoggingApi.setProtocolReceiveMessage(anyString(), anyString(), anyString());
}).thenAnswer(Answers.RETURNS_DEFAULTS);
HttpUtils.logProtocolMessages(mockTarget, HttpClientVersion.HTTP_2, response, null);
mockLog .verify(() -> JcatLoggingApi.setProtocolSendMessage(anyString(), anyString()));
mockLog .verify(() -> LoggingApi.setProtocolReceiveMessage(anyString(), anyString(), anyString()));
}
}
As you can see, the 2 static methods are mocked in the same lambda, both of them instructed to return nothing. I would say that any case going beyond this should consider a redesign (if possible), or even the test itself.
This WILL ONLY work for basic verifications with verify, such as the # of times the mocked methods are invoked. If you try to do more complex checks such as capturing arguments, the limitation of invoking a single static method in the lambda will prevail, and any assertion based on captors will fail because Mockito has not been able to properly inject their values when more than one method in the same mocked static class is invoked.
This is the mockito dependency I used:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>
I recently found out that JUnit > 4.10 allows the usage of #Rule and ExpectedException. Since I'm not big on duplicating code I tried the following. For a better understanding I scaled it down from several tests to just these two. The MockitoJUnitRunner is intentional although it's not used in the small scaled example.
pom.xml
<dependencies>
<!-- Test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
</dependencies>
TestBase
#RunWith(MockitoJUnitRunner.class)
public class TestBase {
/** JUnit > 4.10 allows expected exception handling like this */
#Rule
public ExpectedException exception = ExpectedException.none();
#Before
public void setup() {
this.expectBadParam();
}
protected void expectBadParam() {
this.exception.expect(NullPointerException.class);
}
}
The problem is that the following test is not working as I would expect it to. What I'm trying is by default expect an exception type and in some cases run a normal JUnit test. I can't reset the expected exception once it's set.
public class ExpectedExceptionTest extends TestBase {
#Test
public void error() {
throw new NullPointerException();
}
#Test
public void success() {
this.exception = ExpectedException.none();
// this should be a success
}
}
I already found a different solution by duplicating the expectBadParam method in each method I expect an exception as well as overriding the #Before annotation in the test class. However I'm hoping someone can help me understand why this is not working?
The reason it's not working as you expect (no pun intended) is related to how TestRules work with JUnit.
Effectively what happens is that the test framework inspects the test case for TestRule instances, and then calls the TestRule.apply() method on each on in turn. This method takes a Statement object and returns a Statement(). Your test case object is initially wrapped in a Statement, given to the first TestRule, which returns a brand new Statement wrapping the original Statement. So, basically, the TestRule is being given the opportunity to adapt the original TestCase, generally adding new functionality. Once the framework has gone through all the TestRule instances it calls the Statement.evaluate() method, like it would do for any 'standard' test case it builds up which doesn't have any TestRules attached to it.
The key thing here is that all the interaction between the framework and the TestRule instances happens at test case construction time. Once the test case has been built up, the fields containing the rules are no longer queried or directly interacted with by the test framework. Their main purpose afterwards is for tests to interact with the mutable state contained within the rules. So, if you change the instance field as you do in your test case success() you'll have absolutely no effect on the outcome of the rules, because the rule expecting an IllegalArgumentException has already been applied to the test case.
There's a 'typical' shape to a TestRule implementation. They look like this...
public void apply(Statement base, Description description) {
return new Statement() {
public void evaluate( ) {
// some initialisation
try {
base.evaluate();
} finally {
// some tidy up here
}
}
}
}
Here the TestRule gets an opportunity to run some code after the test case has completed. This is how ExpectedException works (although it has a 'catch Exception(e)' block also). During the course of the test you can call methods on the rule instance which builds up state within the TestRule object which is then used when the finally block is called. So, when you call 'exception.expect(IllegalArgumentException.class)`, the test rule stores a matcher in a list and basically matches caught exceptions using that matcher and any others you may have set up. When you reset the instance field in your test case all that state in the original instance is still there and so the test still fails.
To do what you want to do you need a means of resetting the internal state of the ExpectedException instance. Unfortunately, there are no methods on the ExpectedException class which allow you to remove expectations which have been added. It's only really possible to add expectations. And, to be honest, this is for a good reason - your tests should be logically grouped, with finer grained details being added the closer you get to the test case. The act of 'resetting' expectations is an act of removing rather than adding a detail and so suggests that your tests are not logically grouped well enough. It creates maintainability difficulties if some part of a test suite adds some expectations and another part removes some / all of them.
You have 2 options if you want to use ExpectedException here. The first is to split your test class, or test base class, in two. One suite should be for tests which expect the IllegalArgumentException and another for ones which don't or which have some kind of alternative exception they expect. The second is to accept the duplication inherent in having 44 tests which have to explicitly declare they expect an exception and only 4 tests which don't.
It's possible you may be able to achieve what you want with JUnit Theories in some way, although that would depend very much on how your test cases work.
The solution is to Override the setup method,
You could also do it manually:
#Test
public void success() {
try{
... all your code
} catch (Exception e){
// check your nested clauses
if(e.getCause() instanceof ExpectedException){
// pass
} else {
Assert.fail("unexpected exception");
}
}
Please find bellow interesting links to learn more about :
testing-custom-exceptions-w-junits
Code showing how to test a custom exception by using a Hamcrest
Matcher
Good luck :)
I've been testing my code behavior using TestNG and JMockit for a while now and I have had no specific issue with their combination. Today I came across a situation where I needed to mock one of my internal dependencies, in the so called, type wide manner and I did not need to keep that mock around since none of the test cases dealt with it directly while they counted on the mocked version functionality. So, naturally, I put the mocking logic in my #BeforeMethod. Here is a sample:
public class SampleTest
{
#Mocked
#Cascading
private InnerDependency dependency;
#BeforeMethod
public void beforeMethod()
{
new NonStrictExpectations()
{
{
dependency.getOutputStream((String)any);
result = new Delegate<OutputStream>()
{
public OutputStream getOutputStream(String url)
{
return null;
}
};
}
};
}
#Test
public void testNormalOperation()
{
// The test whose desired behavior depends on dependency being mocked out
// ..
}
}
But, since my tests do not care about the mocked dependency explicitly, I'm not willing to declare it as a test class field, unlike what is done above. To my knowledge of JMockit The only options remaining would be:
Declare dependency as a local mock field:
new NonStrictExpectations()
{
#Cascading
private InnerDependency dependency;
{
//...
}
}
Declare dependency as an input argument for beforeMethod(), similar to what is done for normal #Test methods:
#BeforeMethod
public void beforeMethod(#Mocked #Cascading final InnerDependency dependency)
{
// ...
}
I see that JMockit 1.6+ would not like the first option and warns with WARNING: Local mock field "dependency" should be moved to the test class or converted to a parameter of the test method. Hence, to keep everyone happy, I'm ruling this option out.
But for the second option, TestNG (currently 6.8.6) throws exception when running the test saying java.lang.IllegalArgumentException: wrong number of arguments. I don't see this behavior with normal #Test cases passed with #Mocked parameters. Even playing with #Parameter and #Optional will not help (and should not have!).
So, is there any way I could make this work without declaring the unneccessary test class mock field, or am I missing something here?
Thanks
Only test methods (annotated with #Test in JUnit or TestNG) support mock parameters, so the only choice here is to declare a mock field at the test class level.
Even if not used in any test method, I think it's better than having it declared in a setup method (using #Before, #BeforeMethod, etc.). If it were to be possible, the mock would still have to apply to all tests, because of the nature of setup methods; having a mock field of the test class makes it clear what the scope of the mock is.
Dynamic partial mocking is one more technique to specify #Mocked dependencies locally. However, it has it's limitations (see comments below).
I want to do something like
public static final Option job1 =
OptionBuilder.hasArg(false)
.isRequired(false)
.withDescription("description of job1")
.create(JOB1);
as mentioned How to specify multiple options using apache commons cli?
I am using maven dependency as
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.1</version>
</dependency>
as mentioned here - http://mvnrepository.com/artifact/commons-cli/commons-cli/1.1
But I am not able to, compiler complains
static member org.apache.commons.cli.OptionsBuilder.create() accessed via instance reference
, I even tried with <version>1.2</version>, but no luck, am I missing something?
The problem is that every method in OptionBuilder is static, operating on static fields and returning a single static instance. Hence you don't require an instance of OptionBuilder to execute the methods. This doesn't marry well with the natural desire to chain the calls together, as you've done.
There is no solution other than to either calm the compiler down (perhaps disabling warnings in your IDE?) or adjust your code as follows (untested):
public static final Option job1;
static {
OptionBuilder.hasArg(false);
OptionBuilder.isRequired(false)
OptionBuilder.withDescription("description of job1")
job1 = OptionBuilder.create(JOB1);
}
It would be better if the OptionBuilder class was rewritten with a public no-argument constructor and only instance methods, thus behaving like every other builder out there. There is an existing bug in the commons-cli issue tracker highlighting this: https://issues.apache.org/jira/browse/CLI-224
Update: my patch has been submitted to trunk, so a new "proper" builder will be available in the next release of commons-cli (v1.3). See Javadocs here.
I've got a project that has gwt-log logging lines scattered throughout. Now I'm trying to write some unit tests and nothing seems to be working.
Any class I test that uses the gwt-log facility causes the following exception to be raised:
Caused by: com.googlecode.gwt.test.exceptions.GwtTestConfigurationException:
A custom Generator should be used to instanciate
'com.allen_sauer.gwt.log.client.LogMessageFormatter',
but gwt-test-utils does not support GWT compiler API,
so you have to add our own GwtCreateHandler with
'GwtTest.addGwtCreateHandler(..)' method or to declare your
tested object with #Mock
I have no need for the logger to function during unit tests, I'd prefer to mock it away.
I've attempted to use Mockito to mock the logger, in a few different ways... obviously I have no idea what I'm doing here, none of the following code snippets helped the situation:
public class ClockTest extends GwtTest {
#Mock private LogMessageFormatter lmf;
...
or
...
#Before
public void init() throws Exception {
LogMessageFormatter lmf = mock(LogMessageFormatter.class);
...
Any clues on how to work this out would be most appreciated!
Colin is right, you have 2 ways to deal with your error :
1) Mock the LogMessageFormatter, or at a higher level, mock your Logger instance. gwt-test-utils provides a simple API for mocking with both Mockito or EasyMock : http://code.google.com/p/gwt-test-utils/wiki/MockingClasses
2) provide your own GwtCreateHandler to instanciate the LogMessageFormatter, or at a higher your own Logger instance.
Internally, gwt-log relies on GWT's deferred binding to instanciate a LogMessageFormatter object based on your configuration, which is parsed at compile time. It use GWT's generator API to create the LogMessageFormatter class, but gwt-test-utils is not able to use those kind of Generators.
You'll have to do it "by hand", with gwt-test-utils deferred binding support : GwtCreateHandlers.
Your "LoggerGwtCreateHandler" could use JDK's InvocationHandler and Proxy classes to write a proxy for the Logger interface which would simply silent each method call, since I guess you won't care about any log call in your tests.
Here is a discussion on how to write a GwtCreateHandler : https://groups.google.com/forum/?fromgroups#!topic/gwt-test-utils-users/r_cbPsw9nIE
From the error message you posted:
you have to add our own GwtCreateHandler with
'GwtTest.addGwtCreateHandler(..)' method or to declare your
tested object with #Mock
These are the two options you have to proceed. I've only just begun to work with gwt-test-utils, but the main premise is that it doesn't run the GWT compiler or Dev Mode, so it needs other ways to handle implementing 'magic' features like GWT.create. Its method is to either require you to mock the instance (this should be a fairly common idea in most of your tests for other objects involved in testing) or to provide something like a generator, and hook it up using GwtTest.addGwtCreateHandler.
Building a mock logger shouldn't be too bad, nor should implementing GwtCreateHandler - you just need to make something that has all the log methods. If you want the logging to work, then those methods need to actually invoke some other logger, like java.util.Logger, log4j, slf4j, etc but that is not required for just getting the tests to run (but may be handy for making sure that you logging works, or finding out why your test is failing.
for those still in pain with this damn problem here is what I managed to get (With a lot of pain too ...). It'll solve the conflict between Gwt-test-utils and Gwt-log.
You're of course welcome to modify the format method ;) :
#Before
public void correctLog() {
this.addGwtCreateHandler(new GwtCreateHandler() {
#Override
public Object create(Class<?> classLiteral) throws Exception {
if (classLiteral.isAssignableFrom(LogMessageFormatter.class)) {
return new LogMessageFormatter() {
#Override
public String format(String logLevelText, String category,
String message, Throwable throwable) {
return message + " : " + throwable.getLocalizedMessage();
}
};
}
return null;
}
});
}