Junit 如何正确地单元测试从FTP服务器获取文件的类
事实上,我的问题分为两部分Junit 如何正确地单元测试从FTP服务器获取文件的类,junit,mockito,ftp-client,Junit,Mockito,Ftp Client,事实上,我的问题分为两部分 如何将测试与外部隔离,但仍确保功能正常工作 如何使用Mockito模拟apache commons FtpClient类?当我模拟它时,我会在以下位置得到空: 输入流输入流= ftpClient.retrieveFileStream(ftpParameters.getSourceFileName()) 下面是测试类: 公共类SimpleFtpFileImporterTest{ FtpParameters FtpParameters=新的FtpParameters();
公共类SimpleFtpFileImporterTest{
FtpParameters FtpParameters=新的FtpParameters();
SimpleFtpFileImporter fileImporter=新的SimpleFtpFileImporter();
FTPClient ftpMock=mock(FTPClient.class);
@以前
公共无效启动(){
这个.ftpParams.setServer(“10.0.206.126”);
这个.ftpParams.setPort(21);
这个.ftpParams.setUserName(“mikola”);
此.ftpParams.setPassword(“密码”);
this.ftpParams.setSourceFileName(“readme.txt”);
}
@试验
public void returnNullWhenFileCouldNotBefetchedCompletly()引发IOException{
当(ftpMock.completePendingCommand())。然后返回(false);
fileImporter=新的SimpleFtpFileImporter(ftpMock);
byte[]bytes=fileImporter.downloadFile(ftpParams);
assertNull(字节);
}
}
下面是正在测试的系统:
公共类SimpleFTFileImporter实现IFileImporter{
私人FTP客户FTP客户;
静态记录器Logger=Logger.getLogger(SimpleFtpFileImporter.class);
静止的{
PropertyConfigurator.configure(“config/log4j.properties”);
}
/**
*创建传递FtpClient的SimpleFtpFileImporter类实例。
*此构造函数通过传递任何类型的FTPClient(例如http ftp客户端)来帮助创建单元测试。
*
*@param ftpClient一个ftpClient对象
*/
公共SimpleFtpFileImporter(FTPClient FTPClient){
this.ftpClient=ftpClient;
}
公共SimpleFTFileImporter(){
}
/**
*从指定的FTP服务器获取指定的文件
*
*@param ftpParameters承载所需信息的ftpParameters对象
*@如果成功,返回字节数组中的文件,否则为空
*/
公共字节[]下载文件(FtpParameters FtpParameters){
if(this.ftpClient==null)
this.ftpClient=新的ftpClient();
如果(!ftpParameters.isPropertyPopulated()){
warn(“未设置所有FTP参数。执行将停止。”);
抛出新的FtpParametersNotSetException(“未正确设置Ftp参数”);
}
试一试{
连接(ftpParameters.getServer());
ftpClient.login(ftpParameters.getUserName(),ftpParameters.getPassword());
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY文件类型);
logger.info(“FTP连接已成功建立。正在准备检索文件:”+ftpParameters.getSourceFileName());
InputStream InputStream=ftpClient.retrieveFileStream(ftpParameters.getSourceFileName());
如果(inputStream!=null){
byte[]bytes=IOUtils.toByteArray(inputStream);
布尔成功=ftpClient.completePendingCommand();
logger.info(“收到文件”);
inputStream.close();
如果(成功){
返回字节;
}否则{
logger.warn(“无法完成文件获取过程。返回null”);
返回null;
}
}否则{
logger.warn(“指定了错误的文件名。文件名:”+ftpParameters.getSourceFileName());
抛出新的RuntimeException(“指定了错误的文件名”);
}
}捕获(IOEX异常){
logger.error(“尝试从远程FTP获取文件时出现问题。消息:“+ex.getMessage()+”\n\r“+ex”);
}
返回null;
}
}
虽然我提供了所有需要的参数(主机、端口、用户名和密码)来回答目前为止可以回答的部分,但模拟的FtpClient对象似乎不适合制作真实的东西-您必须学习如何编写可测试的代码;一个好的起点就是这些 你们这边已经有一个误解:似乎被嘲笑的FtpClient对象不适合制作真实的东西 没错。模拟是一个模拟,一个空的测试存根。它没有做任何真实的事情。这就是使用mock的全部意义。它们是空壳,只提供您为它们指定的行为。 我的意思是:Mockito创建的对象不是真正的FtpClient。它只是一个“看起来”像FtpClient的模拟。它没有任何与“真正的”FtpClient“类的连接。换句话说:是的,你可以调用FtpClient拥有的方法,但是它们都是空的。它们什么都不做(好吧,它们做你指定它们做的事情) 要点是:您可以使用mock来将您与外部实现完全解耦。通过为您的测试代码提供mock,您可以忽略“真实”类正在做的一切 查看您的代码和“实际”问题: 为了实现这一点,您必须配置您的模拟,以便在调用
retrieveFileStream()
时返回一些有用的
我的意思是:你已经做到了:
when(ftpMock.completePendingCommand()).thenReturn(false);
告诉Mockito:当调用completePendingCommand()
时,返回false
。您需要对测试代码调用的每个方法执行此操作
除此之外,您的代码还存在许多问题,例如:
public SimpleFtpFileImporter() {
}
不应为空;相反,您应该执行以下操作:
public SimpleFtpFileImporter() {
this(new FtpClient());
}
答案很简单:默认情况下,字段应为最终字段(除非您有充分理由不将其设为最终字段):
编译器会告诉你你忘了初始化这个字段!在你的例子中,绝对有
public SimpleFtpFileImporter() {
this(new FtpClient());
}
private final FTPClient ftpClient;