(原创)Junit中遇到FTP的上传下载该如何Mock

在测试过程中,遇到代码中存在static,final,new对象,ftp需要被mock时,一向很令人头疼,本篇文章,简单介绍一下,ftp的上传下载等方法应该如何mock。

我和我的同事lsj同时对该方法进行测试,采用了两种不同的方案,在下面会依次展示,以及过程中遇到的坑和解决方法。

实例

待测试代码举例,待测method为sendEmailAffix():

@Override 
public Response<BaseDTO> sendEmailAffix(Request<SendEmailRequestDTO> request) {
   BaseDTO baseDTO;
   SendEmailRequestDTO sendDTO = request.getRequestData();
  
   String langType = getLanguageType(sendDTO.getEntId());
   //获取邮件模板
   MessageEmailTemplate messageEmailTemplate = new MessageEmailTemplate();
   messageEmailTemplate.setTemplateType(ServiceConstants.MsgEmailTemplate.*TEMPLATE_TYPE_EMAIL*);
   messageEmailTemplate.setFuncId(ServiceConstants.MsgEmailTemplate.*NEGOTIATION_SUC_CLOUD_SIGN_EMAIL*);
   messageEmailTemplate.setLanguageType(langType);
   MessageEmailTemplate emailTemplate = messageEmailTemplateMapper.queryTemplateContentById(messageEmailTemplate);
   if (null == emailTemplate) {
       baseDTO = new BaseDTO();
       baseDTO.setStatus(false);
       baseDTO.setMsg("mail template empty!");
       *[log](http://log.info/)*[.info](http://log.info/)("templateID-33 mail template empty!");
       return ResponseFactory.*getResponse*(baseDTO, request);
   }
   //替换模板占位符
   String finalContent = emailTemplate.getTemplateContent(); sendDTO.setEmailPerson(emailTemplate.getSender());
   sendDTO.setEmailTitle(emailTemplate.getTitle());
   sendDTO.setEmailMsg(finalContent);
   sendDTO.setAppendix(ServiceConstants.MsgEmailTemplate.*TEMPLATE_LANGUAGE_TYPE_CN*.equals(langType) ?
   "洽谈备忘录.png" : "Negotiation Memo.png");

   //授权发送邮件
   BaseDTO resp = this.accreditSendEmail(sendDTO);
   return ResponseFactory.*getResponse*(resp, request); 
}

public BaseDTO accreditSendEmail(SendEmailRequestDTO sendEmailReq) {
 BaseDTO baseDTO = new BaseDTO();
 baseDTO.setStatus(false);
 //下载本地FTP服务器的附件图片,上传到远端的FTP上
 InputStream inputStream;
 try {
 inputStream = downloadPicFromLocalFTP(sendEmailReq);
 } catch (IOException e) {
 log.error("从gms FTP服务器下载文件失败!{}", e.getMessage());
 baseDTO.setStatus(false);
 baseDTO.setMsg("there is no picture on ftp");
 return baseDTO;
 }
​
 //获得affixId
 String sequence = messageEmailTemplateMapper.querySequence();//16位序列号
 String blankString = "            ";//12位空格
 String affixId = MessagePush.SYSTEM_ID + MessagePush.DISPTYPE_02 + sequence + blankString + ServiceConstants.EmailSendState.EMAIL_SEQUENCE;
​
 //上传签约图片到FTP2服务器
 try {
 uploadPic2RemoteFTP(inputStream, affixId);
 } catch (Exception e) {
 log.error("向邮件FTP服务器上传文件失败!{}", e.getMessage());
 baseDTO.setStatus(false);
 baseDTO.setMsg("upload to mcis's ftp fail");
 return baseDTO;
 }
​
 //发送邮件和附件
 SIPLauncherBean sipBean = sendEmailAccessory(sendEmailReq, affixId);
 if (null != sipBean && null != sipBean.getRespHeader() && "0000000".equals(sipBean.getRespHeader().getMsgcde())) {
 baseDTO.setStatus(true);
 log.info("sendEmailAndAccessory调用结束,返回信息={}", sipBean.getRespHeader().getMsgcde());
 }
​
 log.info("SendEmailServiceImpl   sendEmail end");
 return baseDTO;
 }
​
 //下载FTP1服务器的附件图片
 public InputStream downloadPicFromLocalFTP(SendEmailRequestDTO sendEmailReq) throws IOException {
 FtpEntity ftpEntityIn = new FtpEntity(ConfigUtils.getProperty("ftp.A.ip"),
 ConfigUtils.getProperty("ftp.A.username"),
 ConfigUtils.getProperty("ftp.A.password"),
 Integer.parseInt(ConfigUtils.getProperty("ftp.A.port")));
 InputStream inputStream = null;
 inputStream = new FTPUtil(ftpEntityIn).downloadToStream(
 ConfigUtils.getProperty("ftp.A.picture.address"), sendEmailReq.getPictureName());
 return inputStream;
 }
​
 //上传签约图片到FTP2服务器
 public Boolean uploadPic2RemoteFTP(InputStream inputStream, String affixId) throws IOException {
 FtpEntity ftpEntity = new FtpEntity(ConfigUtils.getProperty("ftp.B.ip"),
 ConfigUtils.getProperty("ftp.B.username"),
 ConfigUtils.getProperty("ftp.B.password"),
 Integer.parseInt(ConfigUtils.getProperty("ftp.B.port")),
 ConfigUtils.getProperty("ftp.B.picture.address"));
 new FTPUtil(ftpEntity).uploadFile(inputStream, affixId);//上传时不带文件后缀
 return true;//上传成功
 }

可观察到,代码中需要测试的method和FTP上传下载method在同一个类中。需要连接FTP服务器进行上传下载图片,而简单的@Mock无法实现对于FTP的模拟。下面提供两种UT测试方法。

添加POM

首先,添加所需的POM依赖,引入powermock

<dependency>
 <groupId>org.powermock</groupId>
 <artifactId>powermock-api-mockito</artifactId>
 <version>${powermock.version}</version>
 <scope>test</scope>
 <exclusions>
 <exclusion>
 <groupId>org.mockito</groupId>
 <artifactId>mockito-all</artifactId>
 </exclusion>
 <exclusion>
 <groupId>org.javassist</groupId>
 <artifactId>javassist</artifactId>
 </exclusion>
 </exclusions>
 </dependency>
 <dependency>
 <groupId>org.powermock</groupId>
 <artifactId>powermock-module-junit4</artifactId>
 <version>${powermock.junit.version}</version>
 <scope>test</scope>
 <exclusions>
 <exclusion>
 <groupId>org.mockito</groupId>
 <artifactId>mockito-all</artifactId>
 </exclusion>
 <exclusion>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 </exclusion>
 <exclusion>
 <groupId>org.javassist</groupId>
 <artifactId>javassist</artifactId>
 </exclusion>
 </exclusions>
 </dependency>
 <dependency>
 <groupId>org.javassist</groupId>
 <artifactId>javassist</artifactId>
 <version>3.20.0-GA</version>
 <scope>test</scope>
 </dependency>

PowerMockito准备

在你写的UT Class前先加@RunWith(PowerMockRunner.class)和@PrepareForTest

@RunWith(PowerMockRunner.class)
@PrepareForTest(SendEmailServiceImpl.class)
public class SendEmailAffixServiceUT extends UTContext {

   @InjectMocks
   private SendEmailServiceImpl sendEmailAffixService;

   @Mock
   private Launcher launcher;

   @Rule
   public TemporaryFolder temporaryFolder = new TemporaryFolder();

   @Mock
   MessageEmailTemplateMapper messageEmailTemplateMapper;

方法一

对new FtpEntity()和new FTPUtil()采用PowerMockito.whenNew(),进行mock

FtpEntity ftpEntityIn = new FtpEntity(ConfigUtils.getProperty("ftp.A.ip"),
 ConfigUtils.getProperty("ftp.A.username"),
 ConfigUtils.getProperty("ftp.A.password"),
 Integer.parseInt(ConfigUtils.getProperty("ftp.A.port")));

Junit代码如下

@Test
 public void test_sendEmailAffix_success() throws Exception{
 SendEmailRequestDTO sendDTO = new SendEmailRequestDTO();
 sendDTO.setEmail("GMS58@cs-boc.cn");
 sendDTO.setTransCode("0151fd79c6974f229d3001dc5889d6a8");
 sendDTO.setPictureName("cloud_sign_0151fd79c6974f229d3001dc5889d6a8.png");
​
 //获取邮件模板
 EntUserLoginInfo entUserLoginInfo = new EntUserLoginInfo();
 entUserLoginInfo.setLanguageType(ServiceConstants.UserLoginLanguageType.CN);
 when(entUserLoginInfoMapper.queryLanguageTypeByEntId(anyString())).thenReturn(entUserLoginInfo);
 MessageEmailTemplate messageEmailTemplateReq = new MessageEmailTemplate();
 messageEmailTemplateReq.setTemplateType(ServiceConstants.MsgEmailTemplate.TEMPLATE_TYPE_EMAIL);
 messageEmailTemplateReq.setFuncId(33);
 MessageEmailTemplate emailTemplateRet = new MessageEmailTemplate();
 emailTemplateRet.setSender("sender");
 emailTemplateRet.setTitle("title");
 emailTemplateRet.setTemplateContent("template content");
 when(messageEmailTemplateMapper.queryTemplateContentById(any(MessageEmailTemplate.class))).thenReturn(emailTemplateRet);
​
 //发送邮件接口
 SIPLauncherBean sipLauncherBean = new SIPLauncherBean();
 LauncherRespHeader respHeader = new LauncherRespHeader();
 respHeader.setMsgcde("0000000");
 sipLauncherBean.setRespHeader(respHeader);
​
 Response<SIPLauncherBean> sipResponse = ResponseFactory.getResponse(sipLauncherBean);
 when(launcher.launch(any(Request.class), any(Class.class))).thenReturn(sipResponse);
​
 FTPUtil mockFtpUtil = PowerMockito.mock(FTPUtil.class);
 PowerMockito.whenNew(FTPUtil.class).withArguments(any(FtpEntity.class)).thenReturn(mockFtpUtil);
 FtpEntity mockFtpEntity = PowerMockito.mock(FtpEntity.class);
 PowerMockito.whenNew(FtpEntity.class).withArguments(anyString(), anyString(), anyString(),anyInt()).thenReturn(mockFtpEntity);
​
 InputStream inputStream = PowerMockito.mock(InputStream.class);
 when(mockFtpUtil.downloadToStream(anyString(), anyString())).thenReturn(inputStream);
 when(mockFtpUtil.uploadFile(any(InputStream.class), anyString())).thenReturn(true);
​
 Response<BaseDTO> resp = sendEmailAffixService.sendEmailAffix(RequestFactory.createRequest(sendDTO));
 Assert.assertTrue(resp.getResponseData().isStatus());
 }

注意:原理通过mock构造函数得到新的对象,该对象的方法可以打桩,官网示例如下


image-20200916195418725.png

示例关键代码段:

FTPUtil mockFtpUtil = PowerMockito.mock(FTPUtil.class);
PowerMockito.whenNew(FTPUtil.class).withArguments(any(FtpEntity.class)).thenReturn(mockFtpUtil);
 FtpEntity mockFtpEntity = PowerMockito.mock(FtpEntity.class);
 PowerMockito.whenNew(FtpEntity.class).withArguments(anyString(), anyString(), anyString(),anyInt()).thenReturn(mockFtpEntity);
​
 InputStream inputStream = PowerMockito.mock(InputStream.class);
 when(mockFtpUtil.downloadToStream(anyString(), anyString())).thenReturn(inputStream);
 when(mockFtpUtil.uploadFile(any(InputStream.class), anyString())).thenReturn(true);

方法二

对FTP uploadFile和downloadToStream方法进行打桩,屏蔽调用方法

@Rule
 public TemporaryFolder temporaryFolder = new TemporaryFolder();
​
 @Test
 public void test_sendEmaiAffix_success_spy() throws Exception{
 SendEmailServiceImpl spy = PowerMockito.spy(sendEmailAffixService);
 SendEmailRequestDTO sendDTO = new SendEmailRequestDTO();
 sendDTO.setEmail("GMS58@cs-boc.cn");
 sendDTO.setTransCode("0151fd79c6974f229d3001dc5889d6a8");
 sendDTO.setPictureName("cloud_sign_0151fd79c6974f229d3001dc5889d6a8.png");
​
 //获取邮件模板
 EntUserLoginInfo entUserLoginInfo = new EntUserLoginInfo();
 entUserLoginInfo.setLanguageType(ServiceConstants.UserLoginLanguageType.CN);
 when(entUserLoginInfoMapper.queryLanguageTypeByEntId(any(String.class))).thenReturn(entUserLoginInfo);
 MessageEmailTemplate messageEmailTemplateReq = new MessageEmailTemplate();
 messageEmailTemplateReq.setTemplateType(ServiceConstants.MsgEmailTemplate.TEMPLATE_TYPE_EMAIL);
 messageEmailTemplateReq.setFuncId(33);
 MessageEmailTemplate emailTemplateRet = new MessageEmailTemplate();
 emailTemplateRet.setSender("sender");
 emailTemplateRet.setTitle("title");
 emailTemplateRet.setTemplateContent("template content");
 when(messageEmailTemplateMapper.queryTemplateContentById(any(MessageEmailTemplate.class))).thenReturn(emailTemplateRet);
​
 //发送邮件接口
 SIPLauncherBean sipLauncherBean = new SIPLauncherBean();
 LauncherRespHeader respHeader = new LauncherRespHeader();
 respHeader.setMsgcde("0000000");
 sipLauncherBean.setRespHeader(respHeader);
​
 //下载上传接口
 File file = temporaryFolder.newFile("test.jpg");
 InputStream inputStream = new FileInputStream(file);
 PowerMockito.doReturn(inputStream).when(spy).downloadPicFromLocalFTP(any(SendEmailRequestDTO.class));
 PowerMockito.doReturn(true).when(spy).uploadPic2RemoteFTP(any(InputStream.class),any(String.class));

 Response<SIPLauncherBean> sipResponse = ResponseFactory.getResponse(sipLauncherBean);
 when(launcher.launch(any(Request.class), any(Class.class))).thenReturn(sipResponse);
​
 Response<BaseDTO> resp = spy.sendEmailAffix(RequestFactory.createRequest(sendDTO));
 Assert.assertTrue(resp.getResponseData().isStatus());
 }

原理,同一类内的方法进行打桩,需要@InjectMock该类,对这个生命的类变量进行spy,PowerMockito.spy(sendEmailAffixService)。然后,对spy的method进行打桩。

官网示例


image-20200916201605225.png

遇到的坑

坑一,运行junit,mockito报错

"C:\Program Files\Java\jdk1.8.0_51\bin\java" -ea -Didea.launcher.port=7533 "-Didea.launcher.bin.path=D:\Program Files (x86)\JetBrains\IntelliJ IDEA 2016.1.3\bin" -Didea.junit.sm_runner -Dfile.encoding=UTF-8 -classpath "D:\Program Files (x86)\JetBrains\IntelliJ IDEA 2016.1.3\lib\idea_rt.jar;D:\Program Files (x86)\JetBrains\IntelliJ IDEA 2016.1.3\plugins\junit\lib\junit-rt.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_51\jre\lib\rt.jar;D:\PROJECT\gms\svn-gms\gpmp-platform\gpmp-platform-service\target\test-classes;D:\PROJECT\gms\svn-gms\gpmp-platform\gpmp-platform-service\target\classes;D:\PROJECT\gms\svn-gms\gpmp-platform\gpmp-platform-dao\target\classes;D:\PROJECT\gms\svn-gms\gpmp-common\target\classes;D:\maven\repository\org\mybatis\mybatis\3.2.7\mybatis-3.2.7.jar;D:\maven\repository\org\mybatis\mybatis-spring\1.2.2\mybatis-spring-1.2.2.jar;D:\maven\repository\org\springframework\spring-tx\4.3.22.RELEASE\spring-tx-4.3.22.RELEASE.jar;D:\maven\repository\org\springframework\spring-jdbc\4.3.22.RELEASE\spring-jdbc-4.3.22.RELEASE.jar;D:\maven\repository\org\springframework\spring-beans\4.3.22.RELEASE\spring-beans-4.3.22.RELEASE.jar;D:\maven\repository\org\springframework\spring-core\4.3.22.RELEASE\spring-core-4.3.22.RELEASE.jar;D:\maven\repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;D:\maven\repository\com\alibaba\druid\1.0.9\druid-1.0.9.jar;D:\maven\repository\com\oracle\ojdbc14\10.2.0.4.0\ojdbc14-10.2.0.4.0.jar;D:\PROJECT\gms\svn-gms\gpmp-platform\gpmp-platform-serviceI\target\classes;D:\maven\repository\com\bocsoft\gaea\gaea-dubbo\1.1.4\gaea-dubbo-1.1.4.jar;D:\maven\repository\org\projectlombok\lombok\1.14.0\lombok-1.14.0.jar;D:\maven\repository\com\bocsoft\gaea\gaea-rudiment-service\1.1.9\gaea-rudiment-service-1.1.9.jar;D:\maven\repository\javax\validation\validation-api\1.1.0.Final\validation-api-1.1.0.Final.jar;D:\maven\repository\org\hibernate\hibernate-validator\5.3.4.Final\hibernate-validator-5.3.4.Final.jar;D:\maven\repository\org\jboss\logging\jboss-logging\3.3.0.Final\jboss-logging-3.3.0.Final.jar;D:\maven\repository\com\fasterxml\classmate\1.4.0\classmate-1.4.0.jar;D:\maven\repository\com\alibaba\dubbo\2.5.3\dubbo-2.5.3.jar;D:\maven\repository\com\alibaba\fastjson\1.2.69\fastjson-1.2.69.jar;D:\maven\repository\com\bocsoft\bocebiz\cbip\cbip-custfaceN-serviceI\0.0.1\cbip-custfaceN-serviceI-0.0.1.jar;D:\maven\repository\org\hibernate\javax\persistence\hibernate-jpa-2.0-api\1.0.1.Final\hibernate-jpa-2.0-api-1.0.1.Final.jar;D:\maven\repository\com\bocsoft\gaea\gaea-log\1.3.1\gaea-log-1.3.1.jar;D:\maven\repository\com\bocsoft\gaea\gaea-exception\1.0.1\gaea-exception-1.0.1.jar;D:\maven\repository\commons-beanutils\commons-beanutils\1.9.2\commons-beanutils-1.9.2.jar;D:\maven\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\maven\repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;D:\maven\repository\org\springframework\spring-context\4.3.22.RELEASE\spring-context-4.3.22.RELEASE.jar;D:\maven\repository\org\springframework\spring-context-support\4.3.22.RELEASE\spring-context-support-4.3.22.RELEASE.jar;D:\maven\repository\org\springframework\spring-aspects\4.3.22.RELEASE\spring-aspects-4.3.22.RELEASE.jar;D:\maven\repository\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar;D:\maven\repository\org\springframework\spring-web\4.3.22.RELEASE\spring-web-4.3.22.RELEASE.jar;D:\maven\repository\org\springframework\spring-aop\4.3.22.RELEASE\spring-aop-4.3.22.RELEASE.jar;D:\maven\repository\com\bocsoft\gaea\gaea-logkafka\0.9.0-RELEASE\gaea-logkafka-0.9.0-RELEASE.jar;D:\maven\repository\org\slf4j\slf4j-api\1.7.26\slf4j-api-1.7.26.jar;D:\maven\repository\org\slf4j\log4j-over-slf4j\1.7.26\log4j-over-slf4j-1.7.26.jar;D:\maven\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\maven\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\maven\repository\org\codehaus\janino\janino\2.6.1\janino-2.6.1.jar;D:\maven\repository\org\codehaus\janino\commons-compiler\2.6.1\commons-compiler-2.6.1.jar;D:\maven\repository\net\sf\ehcache\ehcache\2.10.3\ehcache-2.10.3.jar;D:\maven\repository\org\apache\zookeeper\zookeeper\3.4.10\zookeeper-3.4.10.jar;D:\maven\repository\jline\jline\0.9.94\jline-0.9.94.jar;D:\maven\repository\io\netty\netty\3.10.5.Final\netty-3.10.5.Final.jar;D:\maven\repository\com\github\sgroschupf\zkclient\0.1\zkclient-0.1.jar;D:\maven\repository\commons-net\commons-net\3.3\commons-net-3.3.jar;D:\maven\repository\com\bocsoft\gaea\gaea-common\0.2.3-RELEASE\gaea-common-0.2.3-RELEASE.jar;D:\maven\repository\com\google\zxing\core\3.3.0\core-3.3.0.jar;D:\maven\repository\org\apache\poi\poi-ooxml\3.16\poi-ooxml-3.16.jar;D:\maven\repository\org\apache\poi\poi\3.16\poi-3.16.jar;D:\maven\repository\com\bocsoft\gaea\gaea-rudiment-util\1.1.9\gaea-rudiment-util-1.1.9.jar;D:\maven\repository\com\bocsoft\bocebiz\ezseci\ezseci\0.0.2-SNAPSHOT\ezseci-0.0.2-20160119.015308-1.jar;D:\maven\repository\com\bocsoft\bocebiz\ezsec\ezsec\0.0.2-SNAPSHOT\ezsec-0.0.2-20160119.020406-2.jar;D:\maven\repository\com\bocsoft\gaea\gaea-rudiment-security\1.2.2\gaea-rudiment-security-1.2.2.jar;D:\maven\repository\com\github\pagehelper\pagehelper\4.1.6\pagehelper-4.1.6.jar;D:\maven\repository\com\github\jsqlparser\jsqlparser\0.9.5\jsqlparser-0.9.5.jar;D:\maven\repository\com\bocsoft\gaea\gpmp-finder-serviceI\1.3-SNAPSHOT\gpmp-finder-serviceI-1.3-20200827.022901-3.jar;D:\maven\repository\com\qcloud\qcloud-java-sdk\2.0.1\qcloud-java-sdk-2.0.1.jar;D:\maven\repository\org\quartz-scheduler\quartz\2.2.1\quartz-2.2.1.jar;D:\maven\repository\c3p0\c3p0\0.9.1.1\c3p0-0.9.1.1.jar;D:\maven\repository\com\google\code\gson\gson\2.3.1\gson-2.3.1.jar;D:\maven\repository\org\apache\poi\poi-ooxml-schemas\3.16\poi-ooxml-schemas-3.16.jar;D:\maven\repository\org\apache\xmlbeans\xmlbeans\2.6.0\xmlbeans-2.6.0.jar;D:\maven\repository\stax\stax-api\1.0.1\stax-api-1.0.1.jar;D:\maven\repository\com\github\virtuald\curvesapi\1.04\curvesapi-1.04.jar;D:\maven\repository\commons-codec\commons-codec\1.10\commons-codec-1.10.jar;D:\maven\repository\org\apache\commons\commons-collections4\4.1\commons-collections4-4.1.jar;C:\Program Files\Java\jdk1.8.0_51\jre\..\lib\jconsole.jar;C:\Program Files\Java\jdk1.8.0_51\jre\..\lib\tools.jar;D:\maven\repository\org\javassist\javassist\3.15.0-GA\javassist-3.15.0-GA.jar;D:\maven\repository\com\bocsoft\bocebiz\gms-hsm-serviceI\1.0.0-SNAPSHOT\gms-hsm-serviceI-1.0.0-20190509.023029-11.jar;D:\maven\repository\com\hazelcast\hazelcast\3.4.2\hazelcast-3.4.2.jar;D:\maven\repository\net\sourceforge\findbugs\annotations\1.3.2\annotations-1.3.2.jar;D:\maven\repository\com\eclipsesource\minimal-json\minimal-json\0.9.1\minimal-json-0.9.1.jar;D:\maven\repository\com\hazelcast\hazelcast-wm\3.4.2\hazelcast-wm-3.4.2.jar;D:\maven\repository\commons-io\commons-io\2.4\commons-io-2.4.jar;D:\maven\repository\org\apache\kafka\kafka-clients\0.9.0.1\kafka-clients-0.9.0.1.jar;D:\maven\repository\net\jpountz\lz4\lz4\1.2.0\lz4-1.2.0.jar;D:\maven\repository\org\xerial\snappy\snappy-java\1.1.1.7\snappy-java-1.1.1.7.jar;D:\maven\repository\org\slf4j\jcl-over-slf4j\1.7.13\jcl-over-slf4j-1.7.13.jar;D:\maven\repository\com\lmax\disruptor\3.3.2\disruptor-3.3.2.jar;D:\maven\repository\org\springframework\spring-expression\4.3.22.RELEASE\spring-expression-4.3.22.RELEASE.jar;D:\maven\repository\com\googlecode\junit-toolbox\junit-toolbox\1.8\junit-toolbox-1.8.jar;D:\maven\repository\junit\junit\4.12\junit-4.12.jar;D:\maven\repository\org\codehaus\jsr166-mirror\jsr166y\1.7.0\jsr166y-1.7.0.jar;D:\maven\repository\org\hamcrest\hamcrest-library\1.3\hamcrest-library-1.3.jar;D:\maven\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\maven\repository\org\mockito\mockito-core\1.9.5\mockito-core-1.9.5.jar;D:\maven\repository\org\springframework\spring-test\4.3.22.RELEASE\spring-test-4.3.22.RELEASE.jar;D:\maven\repository\org\mockito\mockito-all\1.9.5\mockito-all-1.9.5.jar;D:\maven\repository\javax\el\javax.el-api\2.2.4\javax.el-api-2.2.4.jar;D:\maven\repository\org\glassfish\web\javax.el\2.2.4\javax.el-2.2.4.jar;D:\maven\repository\com\bocsoft\gaea\gaea-cyclops\1.0.2-RELEASE\gaea-cyclops-1.0.2-RELEASE.jar;D:\maven\repository\com\hazelcast\hazelcast-client\3.4.2\hazelcast-client-3.4.2.jar;D:\maven\repository\com\hazelcast\hazelcast-spring\3.4.2\hazelcast-spring-3.4.2.jar;D:\maven\repository\com\esotericsoftware\kryo\kryo\2.22\kryo-2.22.jar;D:\maven\repository\joda-time\joda-time\2.3\joda-time-2.3.jar;D:\maven\repository\com\bocsoft\bocebiz\dims\dims-java-sdk\1.0.2\dims-java-sdk-1.0.2-jdk17.jar;D:\maven\repository\com\bocsoft\bocebiz\gpmp-smart-match-serviceI\1.1-SNAPSHOT\gpmp-smart-match-serviceI-1.1-20200819.090958-6.jar;D:\maven\repository\org\powermock\powermock-api-mockito\1.6.1\powermock-api-mockito-1.6.1.jar;D:\maven\repository\org\powermock\powermock-api-support\1.6.1\powermock-api-support-1.6.1.jar;D:\maven\repository\org\powermock\powermock-core\1.6.1\powermock-core-1.6.1.jar;D:\maven\repository\org\powermock\powermock-reflect\1.6.1\powermock-reflect-1.6.1.jar;D:\maven\repository\org\objenesis\objenesis\2.1\objenesis-2.1.jar;D:\maven\repository\org\powermock\powermock-module-junit4\1.6.1\powermock-module-junit4-1.6.1.jar;D:\maven\repository\org\powermock\powermock-module-junit4-common\1.6.1\powermock-module-junit4-common-1.6.1.jar" com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 com.bocsoft.bocebiz.gpmp.platform.tdg.email.SendEmailAffixServiceUT,test_sendEmailAffix_success
​
java.lang.VerifyError: Inconsistent stackmap frames at branch target 40
Exception Details:
 Location:
 com/bocsoft/bocebiz/gpmp/platform/tdg/email/SendEmailAffixServiceUT.<init>()V @40: aload_1
 Reason:
 Type uninitializedThis (current frame, locals[1]) is not assignable to 'com/bocsoft/bocebiz/gpmp/platform/tdg/email/SendEmailAffixServiceUT' (stack map, locals[1])
 Current Frame:
 bci: @26
 flags: { flagThisUninit }
 locals: { uninitializedThis, uninitializedThis, top, 'java/lang/Object' }
 stack: { 'java/lang/Object', 'java/lang/Object' }
 Stackmap Frame:
 bci: @40
 flags: { flagThisUninit }
 locals: { uninitializedThis, 'com/bocsoft/bocebiz/gpmp/platform/tdg/email/SendEmailAffixServiceUT' }
 stack: { }
 Bytecode:
 0x0000000: 2a4c 1300 13b8 0019 03bd 000e 1300 1ab8
 0x0000010: 001e b800 244e 2db2 0028 a500 0e2a 01c0
 0x0000020: 002a b700 2ea7 0009 2bb7 0030 0157 2a00
 0x0000030: 0000 0001 4c01 4d13 0032 b800 3503 bd00
 0x0000040: 0e13 0037 b800 38b8 003b 4e2d b200 28a5
 0x0000050: 002f 2dc1 003d 9900 20b8 0043 1300 44b8
 0x0000060: 0035 120e 01b6 004a b600 4e01 b600 52c0
 0x0000070: 0010 4da7 0008 2dc0 0010 4da7 000b bb00
 0x0000080: 1059 b700 544d 2cb5 0057 a700 0301 3a05
 0x0000090: 2ab8 005d b1 
 Stackmap Table:
 append_frame(@40,Object[#12])
 chop_frame(@46,1)
 full_frame(@118,{Object[#12],Top,Top,Object[#14]},{Object[#12]})
 full_frame(@123,{Object[#12],Top,Object[#16]},{Object[#12]})
 full_frame(@126,{UninitializedThis},{UninitializedThis})
 full_frame(@134,{UninitializedThis,Top,Object[#16]},{UninitializedThis})
 full_frame(@141,{Object[#12]},{})
​
​
 at java.lang.Class.getDeclaredMethods0(Native Method)
 at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
 at java.lang.Class.privateGetPublicMethods(Class.java:2902)
 at java.lang.Class.getMethods(Class.java:1615)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.getTestMethods(PowerMockJUnit44RunnerDelegateImpl.java:93)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.<init>(PowerMockJUnit44RunnerDelegateImpl.java:69)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl.<init>(PowerMockJUnit47RunnerDelegateImpl.java:42)
 at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl.<init>(PowerMockJUnit49RunnerDelegateImpl.java:25)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
 at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
 at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:156)
 at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:40)
 at org.powermock.tests.utils.impl.AbstractTestSuiteChunkerImpl.createTestDelegators(AbstractTestSuiteChunkerImpl.java:244)
 at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.<init>(JUnit4TestSuiteChunkerImpl.java:61)
 at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.<init>(AbstractCommonPowerMockRunner.java:32)
 at org.powermock.modules.junit4.PowerMockRunner.<init>(PowerMockRunner.java:34)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
 at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
 at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
 at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
 at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
 at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
 at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
 at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
 at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:36)
 at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:98)
 at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
 at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
 at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:497)
 at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
​
​
Process finished with exit code -1

原因

  1. 使用过旧的字节码生成工具进行类生成。

  2. 使用较旧的JDT编译应用。

解决方法

<dependency>
 <groupId>org.javassist</groupId>
 <artifactId>javassist</artifactId>
 <version>3.20.0-GA</version>
 <scope>test</scope>
 </dependency>

坑二,采用方法二时,尽管使用spy,依然调用了方法内部,并没有被屏蔽。

原因


image-20200916171737303.png

注意:

//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)

笔者尝试发现,当spy的方法是通过new对象引用的时候,使用when(spy.get(0)).thenReturn("foo");会进入到方法内部,而此种情况下doReturn("foo").when(spy).get(0);可以正确打桩。

引用

【1】https://www.jianshu.com/p/a3e551dc7313

【2】https://github.com/powermock/powermock/wiki/Mockito

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335