Mockito ClassCastException - java

The method I want to test has a for loop with logic for each element in bList:
class A {
void someMethod(){
for(B b: bList){
//some logic for b
}
}
}
I get an exception when executing following test:
#RunWith(MockitoJUnitRunner.class)
class ATest {
#Mock
private B b;
#Mock
private Map<Int, List<B>> bMap;
#Mock(answer = Answers.RETURNS_DEEP_STUBS)
private List<B> bList;
#Spy
#InjectMocks
private C c;
....
#Test
public void test(){
//this line executes fine
when(bList.size()).thenReturn(1);
//strangely this works fine
when(bMap.get(any())).thenReturn(bList);
//ClassCastException
when(bList.get(0)).thenReturn(b); // or when(bList.get(anyInt())).thenReturn(b);
c.methodIWantToTest();
}
}
The exception I get is:
java.lang.ClassCastException:
org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$ cannot be cast to xyz.B
Has anyone encountered this before and come up with a workaround?
I have searched for a solution and have come across some links:
http://code.google.com/p/mockito/issues/detail?id=251
and
http://code.google.com/p/mockito/issues/detail?id=107

As this link you posted indicates, you've encountered a bug with Answers.RETURNS_DEEP_STUBS.
I don't actually see any reason to actually use RETURNS_DEEP_STUBS in your example code. You really should try to evaluate whether or not you need deep stubs, because, as the Mockito docs say, "every time a mock returns a mock a fairy dies." So if you can, just take that out and your example will work.
However, if you insist on using deep stubs, you can hack around this error by up-casting the return value from the method call to Object. For example, replace the offending line in your code with this:
when((Object)bList.get(0)).thenReturn(b);
All that being said, I personally agree with #jhericks. The best solution is probably to use an actual ArrayList which contains your mock as opposed to mocking List. The only problem is getting your list injected, so you'd have to use #Spy. For example:
#RunWith(MockitoJUnitRunner.class)
class ATest{
private B b = mock(B.class);
#Spy
private List<B> bList = new ArrayList<B>() {{ add(b); }};
#InjectMocks
private C c = new C();
#Test
public void test(){
c.methodIWantToTest();
// verify results
}
}

Unfortunately this is not possible
Case: tests on API:
interface ConfigurationBuilder {...}
configurationBuilder.newServerAction("s1").withName("111")....create();
Main reason of this usage is compatibility maintenance on compile time.
But mockito cannot support generics in chains with RETURNS_MOCKS and RETURNS_DEEP_STUBS options due to type erasure in java:
Builder/*<ServerActionBuilder>-erasured generic*/ b = configurationBuilder.newServerAction("s1");
b.withName("111")...create();
Result in example above should be ServerAction but in mockito it is Object of generated class.
see Issue: Can not Return deep stubs from generic method that returns generic type #484

Related

Mockito 2.19.0 - Null returned upon static method being used in class method under test, not testable with Mockito?

I'm fairly new to Mockito having gone through their official documentation and a couple of online tutorials in regards to writing tests, as such there is probably something I am missing when I am getting a null returned from a static method I am calling inside a method of a service class under test. I am using Mockito 2.19.0 with assertJ 3.10.0 and the method under test is this:
public Fruit saveFruit(Fruit fruit) {
final String name = fruit.getName().toLowerCase();
Optional<Fruit> fruitOptional = fruitRepository.findOneByName(name);
if (!fruitOptional.isPresent()) {
Fruit newFruit = userDeviceRepository.save(Builder.buildFruitNew(fruit));
LOG.info("saveFruit\t\t->\Fruit saved, {}", newFruit);
return newFruit;
} else {
LOG.info("saveFruit\t\t->\tFruit already exists, updating existing fruit");
Fruit updatedFruit = fruitOptional.map(Builder::buildFruitGet).get();
updatedFruit.setFruitType(fruit.getFruitType());
return fruitRepository.save(updatedFruit);
}
}
The test method I have been trying to write:
#ExtendWith(MockitoExtension.class)
class UserDeviceServiceTest {
#Mock
private FruitRepository fruitRepository;
#InjectMocks
private FruitServiceImpl fruitServiceImpl;
#Test
public void whenSavingNewFruitItShouldReturnTheSavedFruit() {
Fruit newFruit = new Fruit("Lemon", "Yellow");
// Given that a new fruit is saved and returns the new fruit
given(fruitRepository.save(newFruit)).willReturn(newFruit);
// When saving a new fruit
assertThat(fruitServiceImpl.saveFruit(newFruit))
// Then it should return the new fruit
.isSameAs(newFruit);
}
}
When running the test I achieve the following fail message:
java.lang.AssertionError:
Expecting:
<com.fruits.domain.models.Fruit#3bf20acd>
and actual:
<null>
to refer to the same object
EDIT: Added the method I call in the Builder class:
public static Fruit buildFruitNew(Fruit fruit) {
return new Fruit(fruit.getId(), fruit.getType());
}
It seems to me the issue lies with the line where I call the Builder class which contains static methods that return a new instantiated fruit object having had a look at the standard output to see the logger line afterwards which sure enough reports a null object. I have had a read around on here and there was mention PowerMock and JMockit might be needed to test such as class so I assume at the moment it might not possible to test this method because of the static method it uses inside? I know for a fact having already written unit tests for the Builder class that the method used here does return a fruit object with the details of that fruit object passed in so I expected it to run the method without an issue however it seems it doesn't run the method at all. If this is indeed currently not testable code then I imagine if I replaced this static method with a non static method then I would be good to go?
Thanks now.

Is it possible to Declare but not Instatiate a Spied Object in Mockito using #Spy Notation?

I am writing some JUnit tests for legacy code and I am a big fan of using annotations. I would like to know if it is possible to create a declaration to a spied object and later instantiate it. The reason I ask is because I have a class with a non-null constructor. The values for this constructor are not known until after setup of the test cases. The code below shows what I would like to do:
#RunWith(MockitoJUnitRunner.class)
public class ObjectUndertestTest {
#Spy private SomeClassToSpy someClassToSpy;
private Integer parameterOne;
private Integer parameterTwo;
#Before
public void setupTest() {
parameterOne = 1;
parameterTwo = 2;
someClassToSpy = new SomeClassToSpy(parameterOne, parameterTwo);
}
}
The only way that I can see to be able to do this is to mix my syntax and use the traditional spy(object to mock) notation. That is:
#RunWith(MockitoJUnitRunner.class)
public class ObjectUndertestTest {
private SomeClassToSpy someClassToSpy;
private Integer parameterOne;
private Integer parameterTwo;
#Before
public void setupTest() {
parameterOne = 1;
parameterTwo = 2;
someClassToSpy = new SomeClassToSpy(parameterOne, parameterTwo);
SomeClassToSpy spySomeClassToSpy spy(someClassToSpy);
}
}
Or something similar. Any thoughts on this?
Beware that #Spy isn't really a documentation annotation: It is an instruction for MockitoJUnitRunner (et al) to initialize the spy automatically for you according to its documented usage patterns. Though annotations are useful and informative, I think it may cause more confusion to use the annotation for its name and not its semantics.
That said, if it's just a matter of constructing an instance with your chosen constructor arguments, you can call the constructor directly and explicitly and use Mockito's initialization to wrap it in a spy (as in the #Spy docs):
#Spy private SomeClassToSpy someClassToSpy = new SomeClassToSpy(1, 2);
Though you'd be right to favor #Before methods over class initializers or constructors, this is an explicitly-documented method of initialization and one unlikely to cause test pollution or initialization-order problems.

PowerMock whenNew without #PrepareForTest?

This is my situation, I have 2 very simple classes:
public class B {
public void doSomething(){
System.out.println("doSomething B reached");
}
}
And:
public class A {
public void doSomething(){
B b = new B();
b.doSomething();
System.out.println("doSomething A reached");
}
}
I want to test method doSomething of class A with Mockito. Therefor, I want to mock an instance of class B and give this to A when it is instantiating class B. I don't want b.doSomething() to be reached at all, for isolation reasons.
I know I can reach this behaviour by creating the following unittest:
#RunWith(PowerMockRunner.class)
public class TestA {
#Test
#PrepareForTest(A.class)
public void testDoSomethingOfA() throws Exception{
A a = PowerMockito.spy(new A());
B b = PowerMockito.mock(B.class);
PowerMockito.whenNew(B.class).withNoArguments().thenReturn(b);
a.doSomething();
}
}
which results in output:
doSomething A reached
So this work! However, my problem now is that we use the Jococo plugin for test coverage. Jococo doesn't cover code tested with the #PrepareForTest(A.class) statement. And my company values accurate code testing coverage.
My question: Is there another way around to give A an instantiation of B without having to use the #PrepareForTest statement?
Many thanks in advance!
To answer my own question, yes, use an agent: https://github.com/jayway/powermock/wiki/PowerMockAgent
#Rens Groenveld: After integrating PowerMockAgent, did you make any changes in your test class or source code ? I tried integrating PowerMockAgent and removed my main source class from #PrepareForTest but the behavior is same (creating new instance instead of mock).
I have tried jacoco offline instruments and many other solution, It did not work.
I can not post to your comment (needs 50 points) hence added as answer.

How to stub external method properly? NullPointer on mocking statements

No matter what I've tried, test end up on NullPointerException on stubbing statement.
Method to test:
public boolean selectEntity(final List<T> entities) {
if (entities.contains(helper.getLastEntity())) {
return true;
}
}
Above snippet is enough, cause (in unit test) cannot even enter into conditional statement. To clarify: getLastEntity returns field
private T lastEntity
for object of class Helper. T is an interface.
My best try is:
private #Mock Helper helper;
private #Mock List<T> entities;
...
#Test
public void testSelectEntity(){
when(entities.contains(notNull(T.class))).thenReturn(true);
when(helper.getLastEntity()).thenReturn((T) anyObject());
}
How to proceed here?
UPDATE: follow your suggestions, I rewrote test (mocks are for sure initialized this time:))
final DummyT dummyT = new DummyT();
when(helper.getLastEntity()).thenReturn(dummyT);
when(entities.contains(dummyT).thenReturn(true);
assertTrue(objectUnderTest.selectEntity(entities));
where DummyT implements T. Got null pointer on method execution, pointing on if statement.
At least two problems:
You cannot return an instance of the matcher anyObject(). Instantiate an object to return instead.
Depending on your mocking framework, you'll need to initialise mocking first. For example, in Mockito, use: MockitoAnnotations.initMocks(this);

Mockito when method not working

I am using mockito as mocking framework. I have a scenerio here, my when(abc.method()).thenReturn(value) does not return value, instead it returns null.
public class DQExecWorkflowServiceImplTest {
#InjectMocks
DQExecWorkflowServiceImpl dqExecWorkflowServiceImpl = new DQExecWorkflowServiceImpl();
#Mock
private DQUtility dqUtility;
#Mock
private DqExec dqExec;
#Mock
private DqCntlDefn dqCntlDefn;
#Mock
private DqCntlWfDefn dqCntlWfDefn;
#Mock
private DqCntlWfDefnTyp dqCntlWfDefnTyp;
#Mock
private IDQControlWfDefTypeService controlWfDefTypeService;
#Before
public void setUp() throws Exception {
dqExec = new DqExec();
dqCntlWfDefn = new DqCntlWfDefn();
dqUtility = new DQUtility();
dqCntlWfDefnTyp = new DqCntlWfDefnTyp();
dqCntlWfDefnTyp.setDqCntlWfDefnTypCd("MIN_INCLUSIVE_VAL");
dqExecWorkflowServiceImpl
.setControlWfDefTypeService(controlWfDefTypeService);
}
#Test
public void testExecuteWorkflow() {
when(controlWfDefTypeService.getDqCntlWfDefnTypCd(dqCntlWfDefn))
.thenReturn(dqCntlWfDefnTyp);
dqExecWorkflowServiceImpl.executeWorkflow(dqExec, dqCntlWfDefn);
}
}
Java class
#Override
public DqCntlWfExec executeWorkflow(final DqExec dqExec,
final DqCntlWfDefn dqCntlWfDefn) {
final DqCntlWfExec dqCntlWfExec = new DqCntlWfExec();
dqCntlWfExec.setDqCntlWfExecEffDt(dqUtil.getDefaultEffectiveDt());
dqCntlWfExec.setDqCntlWfExecExpDt(dqUtil.getDefaultExpiryDt());
dqCntlWfExec.setDqCntlWfDefn(dqCntlWfDefn);
dqCntlWfExec.setDqExec(dqExec);
final DqCntlWfDefnTyp dqCntlWfDefnTyp = controlWfDefTypeService
.getDqCntlWfDefnTypCd(dqCntlWfDefn);
String workflowType = null;
if(null!=dqCntlWfDefnTyp){
workflowType = dqCntlWfDefnTyp.getDqCntlWfDefnTypCd();
}
When ever i run the test file the when is not working and i am using mockito1.8.5 jar in the buildpath. The service call is being mocked but returns the null value.
final DqCntlWfDefnTyp dqCntlWfDefnTyp = controlWfDefTypeService
.getDqCntlWfDefnTypCd(dqCntlWfDefn);
This object dqCntlWfDefnTyp is null
I have done this before and there was no problem with the when, It seems to be working with files i have done before. I had followed the same procedure for the test file but i couldnt figure out the issue. Can anyone please assist me
Thanks to all the folks in advance
Mockito mock works when we mock the objects loosely.
Here is the change i have made to make it work:
when(controlWfDefTypeService.getDqCntlWfDefnTypCd(any(DqCntlWfDefn.class))
.thenReturn(dqCntlWfDefnTyp);
Instead of passing the object of the Mock class, I passed the class with the Matcher any() and it works.
TL;DR If some arguments in your test are null, be sure to mock the parameter call with isNull() instead of any(SomeClass.class).
Explanation
This might not be the answer that helps OP, but might be useful for someone else. In my case the setup was all good, however, some mocks returned the desired thenReturn(...) value and some didn't.
It's important to understand, that the method call you're trying to mock (i.e. the method in when(someMock.methodToMock)) has to match the actual call and not the signature only.
In my case, I mocked a method with a signature:
public void SomeValue method(String string, SomeParam param)
The call however, in the test was something like:
method("some string during test", null);
Now if you mock the call with:
when(MockedClass.method(anyString(), any(SomeParam.class))
Mockito will not match it even though the signature is correct. The problem is that Mockito is looking for a call of method() with the arguments String and SomeParam, whereas the actual call was with a String and null. What you have to do is:
when(MockedClass.method(anyString(), isNull())
Hint
Since there are many isNull() implementations in different frameworks, be sure to use this one org.mockito.ArgumentMatchers.isNull.
I think I have found your issue, but not all the credit goes to me.
Since you are trying to mock 'dqCntlWfDefnTyp' in your test class and the object itself is being instantiated in the class that you are trying to test, you inevitably run into some issues. The primary problem is that the object cannot be mocked because it is being recreated in during the test.
There are a few options, but the best choice in my humble opinion is using PowerMockito. You will be able to replace the object within the class that is being tested with the one you mock.
An excellent example of this usage of PowerMockito from #raspacorp on this question:
public class MyClass {
void method1{
MyObject obj1=new MyObject();
obj1.method1();
}
}
And the test class...
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class MyClassTest {
#Test
public void testMethod1() {
MyObject myObjectMock = mock(MyObject.class);
when(myObjectMock.method1()).thenReturn(<whatever you want to return>);
PowerMockito.whenNew(MyObject.class).withNoArguments().thenReturn(myObjectMock);
MyClass objectTested = new MyClass();
objectTested.method1();
... // your assertions or verification here
}
}
I had the same problem. The solution for me was to put the Mockito.when(...).thenReturn(...); into the #Before-SetUp method.
Just like Younes EO said: it usually is related to null arguments being passed to mocked functions.
One thing worth adding is that if you're using Kotlin for your tests (and you have mockito-kotlin in your project), for Nullable arguments you should usually use anyOrNull() instead of any().
Relevant to the topic, just in case this helps someone. My mockito.when wasn't working when asserting anyString() reason being the String within the tested class was an injected value from a properties file. The following line set the injected value in the unit test:
ReflectionTestUtils.setField(bean, "theVariable", "theValue");
I haved the same problem when i make test for controler. Use #MockBean instead #Mock

Categories