Hot questions for Using Mockito in classcastexception
Question:
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?
Answer:
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
.
Question:
I have the following method for which I'm trying to write unit test using Mockito. I'm fairly new to Mockito and trying to catch up.
Method to test
public synchronized String executeReadRequest(String url) throws Exception{ String result = null; RestClient client = null; Resource res = null; logger.debug("Start executing GET request on "+url); try{ client = getClient(); res = client.resource(url); result = res.contentType(this.requestType).accept(this.responseType).get(String.class); } catch(Exception ioe){ throw new Exception(ioe.getMessage()); } finally{ res = null; client = null; } logger.info("GET request execution is over with result : "+result); return result; }
The unit test with Mockito
@Test public void testRestHandler() throws Exception { RestHandler handler = spy(new RestHandler()); RestClient mockClient = Mockito.mock(RestClient.class,Mockito.RETURNS_DEEP_STUBS); Resource mockResource = Mockito.mock(Resource.class,Mockito.RETURNS_DEEP_STUBS); doReturn(mockClient).when(handler).getClient(); Mockito.when(mockClient.resource(Mockito.anyString())).thenReturn(mockResource); //ClassCastException at the below line Mockito.when(mockResource.contentType(Mockito.anyString()).accept(Mockito.anyString()).get(Mockito.eq(String.class))).thenReturn("dummy read result"); handler.setRequestType(MediaType.APPLICATION_FORM_URLENCODED); handler.setResponseType(MediaType.APPLICATION_JSON); handler.executeReadRequest("abc"); }
But I'm getting a ClassCastException at the line
Mockito.when(mockResource.contentType(Mockito.anyString()).accept(Mockito.anyString()).get(Mockito.eq(String.class))).thenReturn("dummy read result");
Exception
java.lang.ClassCastException: org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$4b441c4d cannot be cast to java.lang.String
Appreciate any help to resolve this.
Many thanks.
Answer:
This style of chaining during stubbing isn't correct:
Mockito.when( mockResource.contentType(Mockito.anyString()) .accept(Mockito.anyString()) .get(Mockito.eq(String.class))) .thenReturn("dummy read result");
Even though you've set the mocks to return deep stubs, Matchers work via side-effects, so this line doesn't achieve what you think it does. All three matchers (anyString
, anyString
, eq
) are evaluated during the call to when
, and the way you have it your code is likely to throw InvalidUseOfMatchersException
at the slightest provocation—including adding unrelated code or verifications later.
This means your problem isn't the use of eq(String.class)
: It's that Mockito is trying to work the Class matcher in where it doesn't belong.
Instead, you'll need to stub specifically:
Mockito.when(mockResource.contentType(Mockito.anyString())) .thenReturn(mockResource); Mockito.when(mockResource.accept(Mockito.anyString())) .thenReturn(mockResource); Mockito.when(mockResource.get(Mockito.eq(String.class))) // or any(Class.class) .thenReturn("dummy read response");
Note that some of the difficulty here is that Apache Wink uses the Builder pattern, which can be laborious in Mockito. (I've returned mockResource
here, but you could imagine returning specific other Resource objects, at the expense of requiring them in exactly that order later.) A better way might be to use a default Answer that returns this
whenever possible.
Question:
I'm rather new to java and I'm wondering if someone could point me in the correct direction. I'm trying to mock (using mockito) a method that has the following code:
Channel channel = session.openChannel("exec"); ((ChannelExec)channel).setCommand(command); channel.setInputStream(null);
I get a ClassCastException on the line:
((ChannelExec)channel).setCommand(command);
The exception is as follows:
java.lang.ClassCastException: com.jcraft.jsch.Channel$$EnhancerByMockitoWithCGLIB$$15aeab7e cannot be cast to com.jcraft.jsch.ChannelExec
Here is my unit test:
@Test public void testExecuteSSHCommand() throws JSchException, IOException { Channel channel = mock(Channel.class); ChannelExec channelExec = mock(ChannelExec.class); String command = "dummyCommand"; String result = "the correct result"; InputStream inputStream = new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8));; when(channel.getInputStream()).thenReturn(inputStream); when(session.openChannel("exec")).thenReturn(channel); //when(channel.setCommand(command)).get(); logger.info("Returning {}", sshClient.executeSSHCommand(session, command)); assertEquals(result, sshClient.executeSSHCommand(session, command)); }
Channel is an abstract class and ChannelExec is a pojo
Answer:
If you want openChannel to return a ChannelExec
Channel channel = session.openChannel("exec"); ((ChannelExec)channel).setCommand(command);
you need to specify that
when(session.openChannel("exec")).thenReturn(channelExec);
Question:
I am in a situation where I need to Mock two static methods using PowerMocklito. It gives me a mocked object for the first line of code but then the same method is called again but this time it is returning a different object and this throws ClassCastException
.
Method Under test
ESignatureJaxBContextFactory context = (ESignatureJaxBContextFactory) AppContext.getBean("jaxbContextFactory"); /// More code DocusignRESTClient client = (DocusignRESTClient) AppContext.getBean("restServiceClient");
Junit
private ESignatureJaxBContextFactory eSignatureJaxBContextFactory; eSignatureJaxBContextFactory = mock( ESignatureJaxBContextFactory.class ); PowerMockito.when( AppContext.getBean( any( String.class ) ) ).thenReturn( eSignatureJaxBContextFactory );
So above line of code returns me mock context, but I get an exception when it tries to fetch client. How can I test this?
Thanks in advance
Answer:
The problem is that you are mocking AppContext.getBean
for any( String.class )
Try this:
PowerMockito.when(AppContext.getBean("jaxbContextFactory")) .thenReturn(eSignatureJaxBContextFactory); PowerMockito.when(AppContext.getBean("restServiceClient")) .thenReturn(docusignRESTClient);
In this case when AppContext.getBean
is invoked with parameter "jaxbContextFactory"
it will return eSignatureJaxBContextFactory
but not for any other parameters. So you also need to mock invocation with parameter "restServiceClient"
.
Other way of testing it is to provide a set of consecutive return values:
PowerMockito.when(AppContext.getBean(any(String.class))) .thenReturn(eSignatureJaxBContextFactory, docusignRESTClient);
In this case you still mock any invocation of AppContext.getBean
with any String value as parameter, but are telling mockito to return eSignatureJaxBContextFactory
on first invocation and to return docusignRESTClient
on second and any further invocations.
Question:
I am trying to write Junit tests for a Controller class which contains the following method.
@RequestMapping(value = "/mappingUrl", method = RequestMethod.POST) public String uploadFileMethod(HttpServletResponse httpResponse, HttpServletRequest httpRequest, ModelMap model) throws Exception { try { MultipartFile multipartFile = ((MultipartHttpServletRequest) httpRequest).getFile("fileName"); } catch(Exception e){} }
In the test class I have the following method
@Test public void testUploadFileMethod() throws Exception { mockMVC.perform(post("/mappingUrl")).andExpect(status().isOk()); }
I am getting the the below exception when the test is executed:
java.lang.ClassCastException: org.springframework.mock.web.MockHttpServletRequest cannot be cast to org.springframework.web.multipart.MultipartHttpServletRequest
Is there a way I can test the method without changing the existing code? The class is used through out the application and I am afraid I might break something else.
I went through questions that were similar and the following are the ones that came close:
Mockito ClassCastException - A mock cannot be cast
pass remoteUser value in HttpServletRequest to mockmvc perform test
Answer:
Just try
MockMultipartFile myFile = new MockMultipartFile("data", "myFile.txt", "text/plain", "myFileContent".getBytes()); mockMVC.perform(MockMvcRequestBuilders.multipart("/mappingUrl") .file(myFile)).andExpect(status().isOk());
as explained here