Mockito.doThrow不引发任何异常

问题描述

我正在尝试对模拟对象的void方法进行存根以返回异常。这个嘲笑的对象作为对我正在为其编写测试的服务的依赖关系传递。

服务:

@Component
public class FileHandler {

    private static final Logger log = LoggerFactory.getLogger(FileHandler.class);

    private final SSHAccess sshAccess;
    @Value("${datastore.location}")
    private String dataStoreDir;

    public FileHandler(SSHAccess sshAccess){
        this.sshAccess = sshAccess;
    }

    public Either<Pair<Exception,FileRecord>,FileRecord> transferFile(FileRecord fileRecord){
        try {
            var sourceURI = new URI(fileRecord.getSourceURI());
            var digest = sshAccess.execute("md5sum " + sourceURI.getPath())
                    .replaceFirst("([^\\s]+)[\\d\\D]*","$1");
            if (digest.equals(fileRecord.getSourceDigest())) {
                log.info(Thread.currentThread().getName() + ": copying file: " + fileRecord.getId() + " of submission: " + fileRecord.getownedBy());
                sshAccess.download(sourceURI.getPath(),new File(mkdir(dataStoreDir,digest),digest));
                log.info(Thread.currentThread().getName() + ": copying of file: " + fileRecord.getId() + " of submission: " + fileRecord.getownedBy() + " finished.");
                return Either.Right(fileRecord);
            }else{
                log.error("MD5 mismatch for source file {}",sourceURI.getPath());
                return Either.Left(Pair.of(new FileHandlerException("MD5 mismatch"),fileRecord));
            }

        } catch (URISyntaxException
                | IOException
                e) {
            return Either.Left(Pair.of(new FileHandlerException(e),fileRecord));
        }
    }

    private File mkdir(String dataStoreDir,String digest) throws IOException {
        File dir = new File(dataStoreDir,digest.substring(0,3));
            if (!dir.exists() && !dir.mkdirs()) {
                log.error("Unable to create directory {}",dir);
                throw new IOException("Unable to create directory " + dir);
            }
        return dir;
    }
}

测试类别:

@SpringBoottest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class FileHandlerTest {
    private FileHandler fileHandler;

    @Mock
    private SSHAccess sshAccess;

    @BeforeAll
    public void init(){
       fileHandler = Mockito.spy(new FileHandler(sshAccess));
     
    }

        
    @Test
    public void transferFileShouldReturnFileHandlerExceptionOnEitherLeftWhenSSHclientThrowsIOException() throws IOException {
        FileRecord fileRecord = getFileRecord();
        var digest = "6e484ac23110fae10021e";
        when(sshAccess.execute(anyString())).thenReturn(digest);
        doThrow(IOException.class).when(sshAccess).download(anyString(),any(File.class));
        var result = fileHandler.transferFile(fileRecord);
        Assertions.assertTrue(result.getLeft().isPresent()
                && result.getLeft().get().getFirst() instanceof FileHandlerException);
    }

    private FileRecord getFileRecord() {
        var fileRecord = new FileRecord();
        fileRecord.setId(1L);
        fileRecord.setownedBy(1000);
        fileRecord.setSourceURI("scp:host/test/uri/filename");
        fileRecord.setSourceDigest("6e484ac23110fae10021e");
        return fileRecord;
    }
}

但是当我运行此测试用例时,doThrow()不会引发任何异常。方法执行无任何异常,测试失败。我不确定我在做什么错。请帮忙。

解决方法

不确定您为什么要使用@SpringBootTest批注,当运行该应用程序时,该批注将尝试引发与之类似的上下文。因此,在这种情况下,您可以停止实例化FileHandler并仅监视它和SSHAccess bean或使用@MockBean而不是@Mock。

基本上你应该有这样的东西

@SpyBean
private FileHandler fileHandler;

@MockBean
private SSHAccess sshAccess;
,

您正在使用Junit 5。对于Junit 5,您不需要方法@SpringBootTest,需要使用@ExtendWith(MockitoExtension.class)

@SpringBootTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class FileHandlerTest {
    private FileHandler fileHandler;

    @Mock
    private SSHAccess sshAccess;

    @BeforeAll
    public void init(){
       fileHandler = Mockito.spy(new FileHandler(sshAccess));
     
    }
.....
.....
.....
}

也可以尝试Mockito.spy(new FileHandler(sshAccess))代替Mockito.mock(new FileHandler(sshAccess))