26

I have a method in the class AppleProcessor which I would like to test:

public void process(Fruit fruit) {
    if(fruit.getType() == Fruit.APPLE) {
        fruitBasket.add(((AppleFruit) fruit).getApple());
    }
    else {
        // do something else
    }
}

Note that Fruit is an interface with the method getType() which AppleFruit implements and also has a getApple() method.

My test looks like:

@Mock
FruitBasket fruitBasket;

@Mock
Fruit fruit;

@Mock
AppleFruit apple;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

@Test
public void testAnAppleIsProcessed() {
    AppleProcessor appleProcessor = new AppleProcessoer();
    when(fruit.getType()).thenReturn(Fruit.APPLE);
    when(((AppleFruit) fruit).getApple()).thenReturn(apple);

    appleProcessor.process(fruit);

    verify(fruitBasket).add(isA(Apple.class));
}

However I get the following error:

java.lang.ClassCastException: package.fruit.Fruit$$EnhancerByMockitoWithCGLIB$$b8254f54 cannot be cast to package.fruit.AppleFruit

which comes from this line in the test

when(((AppleFruit) fruit).getApple()).thenReturn(apple);

Would anyone know how to resolve this so I can test my code?

user2844485
  • 1,112
  • 3
  • 15
  • 26

5 Answers5

49

When you say

@Mock
Fruit fruit;

You tell Mockito: the fruit variable should be an instance of Fruit. Mockito will dynamically create a class which implements Fruit (this class is Fruit$$EnhancerByMockitoWithCGLIB$$b8254f54), and create an instance of this class. There's no reason for this class to be an instance of AppleFruit, since you didn't tell Mockito that the object had to be of type AppleFruit.

Declare it as AppleFruit, and it will be of type AppleFruit.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
13

To anyone searching for this just include:

@Mock(extraInterfaces = {AppleFruit.class})
Fruit fruit;

Which will add an extra interface to the mock and the casting wont raise any exceptions.

4

Mockito can deal with mocked objects that are already casted at mocking time (assignment). However, it does not cast by itself a mocked object during code execution.

In other words(or better yet, code):

Fruit fruit = Mockito.mock(Applefruit.class);

Just do as JB Nizet said and you will be fine. I had a similar problem and his solution worked.

For this question it would be:

@Mock
FruitBasket fruitBasket;

@Mock
AppleFruit fruit; // changed here

@Mock
AppleFruit apple;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

@Test
public void testAnAppleIsProcessed() {
    AppleProcessor appleProcessor = new AppleProcessoer();
    when(fruit.getType()).thenReturn(Fruit.APPLE);
    when(((AppleFruit) fruit).getApple()).thenReturn(apple);

    appleProcessor.process(fruit);

    verify(fruitBasket).add(isA(Apple.class));
}

That is all what is needed.

1

You can instruct mockito to return an object of subclass type, for a method which returns a super-class object. Then you won't need to tell mockito to cast the object.

  • 3
    An example of this would be very useful... Unless you mean simply declare it as AppleFruit... – jb62 Aug 27 '19 at 23:05
0

Your mock object is enhanced by Mockito and it is not same as your class, so you can't type cast.