ClassCastException on attempt to mock Querydsl SQLQueryFactory - mockito

Trying to mock SQLQueryFactory of Querydsl for DAO unit testing. Using Mockito's deep stub for the very first time.
Below is the minimal code which fails
#Test
void tryMockQueryDsl() {
SQLQueryFactory sql = Mockito.mock(SQLQueryFactory.class, Mockito.RETURNS_DEEP_STUBS);
Mockito.when(sql.select(ArgumentMatchers.<Expression<?>>any())
.from(ArgumentMatchers.<Expression<?>>any())
.fetchFirst()
).thenReturn(null);
}
with the following exception:
java.lang.ClassCastException: class com.querydsl.sql.ProjectableSQLQuery$MockitoMock$1584151766 cannot be cast to class com.querydsl.sql.SQLQuery (com.querydsl.sql.ProjectableSQLQuery$MockitoMock$1584151766 and com.querydsl.sql.SQLQuery are in unnamed module of loader 'app')
What can be the problem?

Mocks can not be cast. Instead of RETURN_DEEP_STUBS mock each method on its own and return a mocked instance of the expected class.
If you do not want to suppress the warnings you will get for not defining the generic types, you can use the #Mock annotation instead to create the mocks, like described here.
This example doesn't make much sense for a testcase (as it tests nothing), but its a showcase on how to avoid the exception.
#RunWith(MockitoJUnitRunner.class)
public class Test {
#Test
public void tryMockQueryDsl() {
ProjectableSQLQuery projectableQuery = Mockito.mock(ProjectableSQLQuery.class);
// not really needed as this is the default behaviour
Mockito.when(projectableQuery.fetchFirst()).thenReturn(null);
SQLQuery query = Mockito.mock(SQLQuery.class);
Mockito.when(query.from(ArgumentMatchers.<Expression<?>>any())).thenReturn(projectableQuery);
SQLQueryFactory sql = Mockito.mock(SQLQueryFactory.class);
Mockito.when(sql.select(ArgumentMatchers.<Expression<?>>any())).thenReturn(query);
Expression expr = Mockito.mock(Expression.class);
sql.select(expr).from(expr).fetchFirst();
}
}

Related

Mock constructor of a class

I am writing test class for my java class. I am using Junit5 with Mockito.
I am using Junit5 which isnt compatible with Power Mockito so I am using Mockito only.
I have class Emp which have function findSalary like below and EmpProfileClient is initialized at constructor.
Class Emp {
......
public void findSalary(empId) {
...
TaxReturn taxReturn = new TaxReturn(EmpProfileClient);
int value = taxReturn.apply(new TaxReturnRequest.withEmpId(empId))
.returnInRupee();
...
}
}
When I am writing the test case, I mocked EmpProfileClient, but since we are creating TaxReturn in a method, How I can mock TaxReturn.apply so I can write the expectation to get the value as per my choice which I set in the test class?
If you want to mock this, the TaxReturn class should be an injected bean in the Emp class. Add an injection framework (like Spring) and inject the TaxReturn class. In the test you write you can inject a Mock instead of the real class. See #InjectMocks annotation of the mockito framework.
If I understood your question correctly(you are looking for mocking taxReturn.apply) I'd suggest next:
First. Refactor your taxReturn instantiation(as it is would be much easier to mock method behavior in comparison for trying to mock local variable)
public class EmpService {
public int findSalary(Integer empId) {
//...
// It's doesn't matter what the actual empProfileClient type is
// as you mocking creation behavior anyway
Object empProfileClient = null;
TaxReturn taxReturn = createClient(empProfileClient);
int value = taxReturn.apply(new TaxReturnRequest().withEmpId(empId))
.returnInRupee();
//...
return value; // or whatever
}
protected TaxReturn createClient(Object empProfileClient) {
return new TaxReturn(empProfileClient);
}
}
Second. Use Mockito.spy() in your test:
class EmpServiceTest {
#Test
void findSalary() {
TaxReturn taxReturn = Mockito.mock(TaxReturn.class);
// this is the main idea, here you using partial EmpService mock instance
// part is mocked(createClient()) and other part(findSalary()) is tested
EmpService service = Mockito.spy(EmpService.class);
when(service.createClient(any())).thenReturn(taxReturn);
when(taxReturn.apply(any(TaxReturnRequest.class))).thenReturn(taxReturn);
int yourExpectedValue = 5;
when(taxReturn.returnInRupee()).thenReturn(yourExpectedValue);
assertEquals(yourExpectedValue, service.findSalary(0));
}
}
Keep in mind that any(), spy(), when() and mock() methods are part of Mockito API. So there is nothing hidden here

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.

Caused InvalidUseOfMatchersException for clearly mocked class

I got error while running JUnit test with Mockito's matcher
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 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"));
Here is source code.
class A
{
public String getField()
{
return "hi";
}
}
#Test
public void testA()
{
final A a = mock(A.class);
when(a.getField()).thenReturn(Matchers.any(String.class));
a.getField();
}
What is problem here? Please open my eyes!
You are using an argument matcher: Matchers.any(String.class). An argument matcher is not intended to be used as a return a value of a stubbed method.
An argument matcher should be used when you need to customize the way a method is stubbed :
when(a.sayHello(Matchers.any(String.class))).thenReturn("Hello");
In your example, you must return an instance of String and not a matcher :
when(a.getField()).thenReturn("theFieldValue");
You have made the classic error of mocking the class that you're trying to test. The whole point of mocking is that you remove other classes from consideration by your test. So if you're testing a class A that uses an object of class B in some way, you might make a mock of class B. But you wouldn't mock the class that you're actually testing, because then you are no longer testing the class, but testing the mocking framework.
In order to test the method you've supplied, it doesn't make sense to use Mockito at all; because there's no additional class that you want to remove from consideration by your test. The only class is A - the one you're testing.
Your test should just be the following
public class TestA {
private A toTest = new A();
#Test
public void getFieldReturnsHi() {
assertEquals("Hi", toTest.getField());
}
}

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.

JUnit #Before method ordering in Groovy

I am used to JUnit running #Before methods in a superclass before #Before methods in a subclass. However, I've got a Groovy test class which inherits from another Groovy class, and they both contain #Before methods; the problem I have is that #Before method in the test class is running before the one in its superclass, and I'm getting NPEs from uninitialised variables (the superclass is supposed to take care of that).
The superclass is something like this:
import groovyx.net.http.RESTClient
import org.junit.Before
abstract class BaseTestClass {
def client
#Before
void setUp() {
client = new RESTClient()
}
}
And the subclass is something like this:
import org.junit.Before
class TestClass extends BaseTestClass {
#Before
void setUp() {
client.post(path: '/entity', body: '{"id":"test"}')
}
...
}
This is a simplified version, but I get the error: java.lang.NullPointerException: Cannot invoke method post() on null object in the setUp() method of the subclass. Any ideas what could cause this behaviour? All the docs say it should be the other way round, and I've never previously experienced any different.
I'm running using the maven-failsafe-plugin, junit-4.10 and jdk-1.6.0_31. Interestingly, I have other Groovy test classes in the same place (same package, same project, same directory) which do not suffer from this problem - the ordering of #Before methods is correct; furthermore, it appears to be deterministic - it's always the same test class that has the problem.
Thanks!
You named both of your #Before methods setUp(). The child's setUp() method overrides the parent's one. So the line client = new RESTClient() is never called.
Just pick another name.

Resources