Search code examples
javaunit-testingjunitmockitopowermockito

How to mock typecast instances in Mockito


I have a method that SFTPs a file. In the method I have the following snippet of code:-

Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
JSch jsch = new JSch();
try (FileInputStream fileInputStream = new FileInputStream(new File(fileName));){
    session = jsch.getSession(sftpUser, sftpHost, sftpPort);
    session.setPassword(sftpPass);
    java.util.Properties config = new java.util.Properties();
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);
    session.connect();
    log.info("Host connected.");
    channel = session.openChannel("sftp");
    channel.connect();
    log.info("sftp channel opened and connected.");
    channelSftp = (ChannelSftp) channel;
    channelSftp.cd(sftpWorkingFolder);
    channelSftp.put(fileInputStream, new File(fileName).getName());
} catch (JSchException | SftpException | IOException e) {
    log.error("Exception : ", e);
}

I am writing the Junit test method for the above. How to mock the instance of channelSftp which is just the channel with a typecast?

Below is a snippet of the test method:

@MockBean
private JSch jSch;
@Mock
FileInputStream fileInputStream;
@MockBean
private Session session;
@MockBean
private Channel channel;
@MockBean
private ChannelSftp channelSftp;

PowerMockito.whenNew(JSch.class).withNoArguments().thenReturn(jSch);
PowerMockito.whenNew(FileInputStream.class).withAnyArguments().thenReturn(fileInputStream);
when(jSch.getSession("ddmin", "localhost:8080", 22)).thenReturn(session);
doNothing().when(session).connect();
when(session.openChannel("sftp")).thenReturn(channel);
doNothing().when(channel).connect();
doNothing().when(channelSftp).cd(any(String.class));

Solution

  • You can't use @MockBean while using PowerMockito since the latest requires PowerMockRunner @RunWith(PowerMockRunner.class) while MockBean requires SpringRunner @RunWith(SpringRunner.class)

    Instead, use Mockito's @Mock and PowerMockRunner, also don't forget to prepare for test the class which has the method you are testing.

    And replace your channel with channelSftp when session.openChannel is called

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(ClassThatHasMethodToBeTested.class)
    public class JSchTest
    {
        @Mock
        private JSch jSch;
        @Mock
        FileInputStream fileInputStream;
        @Mock
        private Session session;
        @Mock
        private Channel channel;
        @Mock
        private ChannelSftp channelSftp;
    
        @Test
        public void someTest() throws Exception
        {
            MockitoAnnotations.initMocks(this.getClass());
    
            PowerMockito.whenNew(JSch.class)
                    .withNoArguments()
                    .thenReturn(jSch);
            PowerMockito.whenNew(FileInputStream.class)
                    .withAnyArguments()
                    .thenReturn(fileInputStream);
            when(jSch.getSession("ddmin", "localhost:8080", 22)).thenReturn(session);
            doNothing().when(session)
                    .connect();
            when(session.openChannel("sftp")).thenReturn(channelSftp); // channelSftp instead of channel
            doNothing().when(channelSftp)
                    .connect();
            doNothing().when(channelSftp)
                    .cd(any(String.class));
        }
    }