Mockito - You cannot use argument matchers outside of verification or stubbing - have tried many things but still no solution - junit

I have the following piece of code:
PowerMockito.mockStatic(DateUtils.class);
//And this is the line which does the exception - notice it's a static function
PowerMockito.when(DateUtils.isEqualByDateTime (any(Date.class),any(Date.class)).thenReturn(false);
The class begins with:
#RunWith(PowerMockRunner.class)
#PrepareForTest({CM9DateUtils.class,DateUtils.class})
And I get org.Mockito.exceptions.InvalidUseOfMatchersException...... You cannot use argument matchers outside of verification or stubbing..... (The error appears twice in the Failure Trace - but both point to the same line)
In other places in my code the usage of when is done and it's working properly. Also, when debugging my code I found that any(Date.class) returns null.
I have tried the following solutions which I saw other people found useful, but for me it doesn't work:
Adding
#After
public void checkMockito() {
Mockito.validateMockitoUsage();
}
or
#RunWith(MockitoJUnitRunner.class)
or
#RunWith(PowerMockRunner.class)
Change to
PowerMockito.when(new Boolean(DateUtils.isEqualByDateTime(any(Date.class), any(Date.class)))).thenReturn(false);
Using anyObject() (it doesn't compile)
Using
notNull(Date.class) or (Date)notNull()
Replace
when(........).thenReturn(false);
with
Boolean falseBool=new Boolean(false);
and
when(.......).thenReturn(falseBool);

As detailed on the PowerMockito Getting Started Page, you'll need to use both the PowerMock runner as well as the #PrepareForTest annotation.
#RunWith(PowerMockRunner.class)
#PrepareForTest(DateUtils.class)
Ensure that you're using the #RunWith annotation that comes with JUnit 4, org.junit.runner.RunWith. Because it's always accepted a value attribute, it's pretty odd to me that you're receiving that error if you're using the correct RunWith type.
any(Date.class) is correct to return null: Rather than using a magic "matches any Date" instance, Mockito uses a hidden stack of matchers to track which matcher expressions correspond to matched arguments, and returns null for Objects (and 0 for integers, and false for booleans, and so forth).

So in the end,what worked for me was to export the line that does the exception to some other static function. I called it compareDates.
My implementation:
In the class that is tested (e.g - MyClass)
static boolean compareDates(Date date1, Date date2) {
return DateUtils.isEqualByDateTime (date1, date2);
}
and in the test class:
PowerMockito.mockStatic(MyClass.class);
PowerMockito.when(MyClass.compareDates(any(Date.class), any(Date.class))).thenReturn(false);
Unfortunately I can't say I fully understand why this solution works and the previous didn't.
maybe it has to do with the fact that DateUtils class is not my code, and I can't access it's source, only the generated .class file, but i'm really not sure about it.
EDIT
The above solution was just a workaround that did not solve the need to cover the DateUtils isEqualByDateTime call in the code.
What actually solved the real problem was to import the DateUtils class which has the actual implementation and not the one that just extends it, which was what I imported before.
After doing this I could use the original line
PowerMockito.mockStatic(DateUtils.class);
PowerMockito.when(DateUtils.isEqualByDateTime (any(Date.class),any(Date.class)).thenReturn(false);
without any exception.

I had a similar problem with TextUtils in my Kotlin Test Class
PowerMockito.`when`(TextUtils.isEmpty(Mockito.anyString())).thenReturn(true)
Resolved it by adding below code on top of my Test Class
#PrepareForTest(TextUtils::class)
and called mockStatic this before PowerMockito.`when`
PowerMockito.mockStatic(TextUtils::class.java)

Related

ConsoleLauncher returns 0 although class-under-test could not be loaded

We run a set of tests in a CI pipeline and call our test classes like this:
java -classpath junit-jupiter-api-5.0.1.jar:junit-platform-console-standalone-1.0.1.jar org.junit.platform.console.ConsoleLauncher --select-class xy.Test
If class xy.Test cannot be found on the classpath an error message appears but ConsoleLauncher's return value is 0! Since our CI system runs unattended the return value is the only important return value!
As I have seen this behaviour got updated in JUnit 5.0.0 M2 but I regard this as I mistake: If I define a class by --select-class and the class cannot be found then something has gone wrong!
As I countermeasure I hacked (by means of introspection) org.junit.platform.commons.util.BlacklistedExceptions by overwriting blacklist's field with OutOfMemoryError (=default) and PreconditionViolationException (=case where class could not be found).
(If the standard behaviour shall not be changed...) I think there should be a better way to get this behaviour!

Testing type matching differences in Java 6 and Java 8

I updated an application JDK from 1.6 to 1.8 but I kept the language level 1.6 in IntelliJ.
After updating I got compilation error in some tests in assertThat statements with checking type of an object. The code is like this:
assertThat((Class) myList.get(0).getMyClassType(), is(equalTo(MySubclass.class)));
myList is looking like this:
List<MyClassDefinition> myList = myClassDefinition.getMyClassDefinitions(reader);
Where definition of MyClassDefinition and getMyClassType() are like this:
public class MyClassDefinition {
private Class<? extends MyClass> classType;
public Class<? extends MyClass> getMyClassType() {
return classType;
}
}
and MySubclass is Myclass's subclass:
public class MySubclass extends MyClass {
#Override
public void initialise() {
// some action here!
}
}
The definition of MyClass is
public abstract class MyClass extends AnotherClass<AnotherType>{
//Definitions
}
The import for Assert is and equals library is this:
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
and the hamcrest version is hamcrest-all-1-3
After changing project SDK to jdk 1.8 I am getting this error message:
Error:(136, 9) java: no suitable method found for assertThat(java.lang.Class,org.hamcrest.Matcher<java.lang.Class<MySubClass>>)
method org.hamcrest.MatcherAssert.assertThat(java.lang.String,boolean) is not applicable
(argument mismatch; java.lang.Class cannot be converted to java.lang.String)
method org.hamcrest.MatcherAssert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<? super T>) is not applicable
(cannot infer type-variable(s) T
(actual and formal argument lists differ in length))
method org.hamcrest.MatcherAssert.<T>assertThat(T,org.hamcrest.Matcher<? super T>) is not applicable
(cannot infer type-variable(s) T
(argument mismatch; org.hamcrest.Matcher<java.lang.Class<MySubClass>> cannot be converted to org.hamcrest.Matcher<? super java.lang.Class>))
application is build with Ant and we have added hamcrest jar file to class file, so there is no change when we are altering JDK in project.
So my question is why this code is working with JDK 1.6 but not working with 1.8 while I am using same level of language (1.6) for compilation? Is it depend to different libraries some how?
Apparently, you had a problem with the generic type signatures which you worked around by inserting a type cast to the raw type Class, which causes the compiler to treat the entire statement as an unchecked operation using raw types only.
As you can see from the compiler message, org.hamcrest.Matcher<java.lang.Class<MySubClass>> cannot be converted to org.hamcrest.Matcher<? super java.lang.Class>, it now did a generic type check which (correctly) failed, but imho, it shouldn’t do that type check under Java 6 language rules. The problem stems from the fact that JDK8 doesn’t include the original Java 6 compiler but rather let the new compiler attempt to compile using the old rules, which may not be that precise.
But regardless of whether the behavior is correct or not, I wouldn’t expect a fix for it, as emulating the old Java 6 language rules is not of a high priority.
Note that with source level 1.8, the code compiles without problems, even without the raw type cast. The original problem stems from the restrictive signature of CoreMatchers.equalTo(…). The standalone expression equalTo(InstanceOfFoo) returns a Matcher<Foo>, which being passed to assertThat allows to only test instances of Foo (it’s even worse when using isA(Foo.class) which also can only test instances of Foo, which makes the test pointless).
With Java 8, there is target type inference, which allows, e.g.
Matcher<Object> m = equalTo(InstanceOfFoo);, which will infer Object for <T> and passes, as InstanceOfFoo is also assignable to Object. This also works in conjunction with the compound assertThat statement of your question, inferring a suitable type.
This guides us to the general solution that works with all language levels. Just use
assertThat(myList.get(0).getMyClassType(), is(equalTo((Object)MySubclass.class)));
Class<MySubclass> is, of course, assignable to Object which makes the cast a no-op. But then, getting a Matcher<Object>, you can check every object you like, including the result of myList.get(0).getMyClassType(), which is, of course, also assignable to Object. Unlike your original workaround, this doesn’t bear any raw type usage nor unchecked operation.
You could also use an explicit type instead of a cast, CoreMatchers.<Object>equalTo(MySubclass.class), but this eliminates the benefit of import static.
By the way, when matching Class objects, you may use sameInstance instead of equalTo.

Calling mock method instead of real method with Mockito

I have a method which needs to be called instead of the real method.
Instead I get an exception. Can somebody please help me with right way to call the alternate method through mockito ?
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 4 recorded.
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
//Code starts here
class A{
public realMethod(String s, Foo f){
}
}
class B {
public mockMethod(String s, Foo f) {
}
}
class UnitTestClass{
ClassA mock = new ClassA();
mock.when(realMethod(any(String.class), any(Foo.class))).thenReturn(mockMethod(any(String.class),any(Foo.class));
}
You are getting mocking wrong.
Here:
thenReturn(mockMethod(any(String.class),any(Foo.class));
That simply doesn't make sense.
Mocking works like this:
you create a mock object of some class, like A mock = mock(A.class)
you specify interactions on that mock object
Your code implies that you think that these specifications are working like "normal" code - but they do not!
What you want to do: when some object is called with certain parameters, then return the result of another method call.
Like in:
when(a.foo(x, y)).thenReturn(b.bar(x, y))
That is what want you intend to do. But thing is: it isn't that easy. You can't use the any() matcher in thee thenReturn part in order to "provide" the arguments that were passed in the when() call before! It is that simply.
Mocking should be within a specific unit test to get a specific result.
Meaning: you are not writing an ordinary program where it would make any sense to "forward" parameters to another call. In other words; your code should more look like:
when(mock.realMethod("a", someSpecificFoo)).thenReturn(mockMethod("a", someSpecificFoo))
That is the only thing possible here.
Beyond that, you might want to look into a Mockito enter link description here instead.
Long story short: it simply looks like you don't understand how to use mocking frameworks. I suggest that you step back and read/work various tutorials. This is not something you learn by trial and error.

Test Failure Message in mockito : Argument(s) are different! Wanted:

I am testing a Restful endpoint in my JUnit and getting an exception as below in the
list which is present as an argument inside the save method,
**"Argument(s) are different! Wanted:"**
save(
"121",
[com.domain.PP#6809cf9d,
com.domain.PP#5925d603]
);
Actual invocation has different arguments:
save(
"121",
[com.domain.PP#5b6e23fd,
com.domain.PP#1791fe40]
);
When I debugged the code, the code broke at the verify line below and threw the
above exception. Looks like the arguments inside the "testpPList" within the save
method is different. I dont know how it becomes different as I construct them in my
JUNit properly and then RestFul URL is invoked.
Requesting your valuable inputs. Thanks.
Code:
#Test
public void testSelected() throws Exception {
mockMvc.perform(put("/endpointURL")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(testObject)))
.andExpect(status().isOk());
verify(programServiceMock, times(1)).save(id, testpPList);
verifyNoMoreInteractions(programServiceMock);
}
Controller method:
#RequestMapping(value = "/endpointURL", method = RequestMethod.PUT)
public #ResponseBody void uPP(#PathVariable String id, #RequestBody List<PPView> pPViews) {
// Code to construct the list which is passed into the save method below
save(id, pPList);
}
Implementing the Object#equals(Object) can solve it by the equality comparison. Nonetheless, sometimes the object you are validating cannot be changed or its equals function can not be implemented. For such cases, it's recommended using org.mockito.Matchers#refEq(T value, String... excludeFields). So you may use something like:
verify(programServiceMock, times(1)).save(id, refEq(testpPList));
Just wrapping the argument with refEq solves the problem.
Make sure you implement the equals method in com.domain.PP.
[Edit]
The reasoning for this conclusion is that your failed test message states that it expects this list of PP
[com.domain.PP#6809cf9d, com.domain.PP#5925d603]
but it's getting this list of PP
[com.domain.PP#5b6e23fd, com.domain.PP#1791fe40]
The hex values after the # symbol for each PP object is their hash codes. Because they are different, then it shows that they belong to different objects. So the default implementation of equals will say they're not equal, which is what verify() uses.
It's good practice to also implement hashCode() whenever you implement equals(): According to the definition of hashCode, two objects that are equal MUST have equal hashCodes. This ensures that objects like HashMap can use hashCode inequality as a shortcut for object inequality (here, placing objects with different hashCodes in different buckets).

JUnit Easymock Unexpected method call

I'm trying to setup a test in JUnit w/ EasyMock and I'm running into a small issue that I can't seem to wrap my head around. I was hoping someone here could help.
Here is a simplified version of the method I'm trying to test:
public void myMethod() {
//(...)
Obj myObj = this.service.getObj(param);
if (myObj.getExtId() != null) {
OtherObj otherObj = new OtherObj();
otherObj.setId(myObj.getExtId());
this.dao.insert(otherObj);
}
//(...)
}
Ok so using EasyMock I've mocked the service.getObj(myObj) call and that works fine.
My problem comes when JUnit hits the dao.insert(otherObj) call. EasyMock throws a *Unexpected Method Call* on it.
I wouldn't mind mocking that dao in my test and using expectLastCall().once(); on it, but that assumes that I have a handle on the "otherObj" that's passed as a parameter at insert time...
Which of course I don't since it's conditionally created within the context of the method being tested.
Anyone has ever had to deal with that and somehow solved it?
Thanks.
You could also use EasyMock.isA(OtherObj.class) for a little more type safety.
If you can't get a reference to the object itself in your test code, you could use EasyMock.anyObject() as the expected argument to yourinsert method. As the name suggests, it will expect the method to be called with.. well, any object :)
It's maybe a little less rigorous than matching the exact argument, but if you're happy with it, give it a spin. Remember to include the cast to OtherObjwhen declaring the expected method call.
The anyObject() matcher works great if you just want to get past this call, but if you actually want to validate the constructed object is what you thought it was going to be, you can use a Capture. It would look something like:
Capture<OtherObj> capturedOtherObj = new Capture<OtherObj>();
mockDao.insert(capture(capturedOtherObj));
replay(mockDao);
objUnderTest.myMethod();
assertThat("captured what you expected", capturedOtherObj.getValue().getId(),
equalTo(expectedId));
Also, PowerMock has the ability to expect an object to be constructed, so you could look into that if you wanted.
Note also that if you use EasyMock.createStrictMock();, the order of the method calls is also important and if you break this rule, it would throw an unexpected method call.