博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
PowerMock注解PowerMockIgnore的使用方法
阅读量:4596 次
发布时间:2019-06-09

本文共 5315 字,大约阅读时间需要 17 分钟。

故事要从一个异常开始,某天我在开发一个加密、解密特性,算法使用的是3DES,样例代码如下。

 

package org.jackie.study.powermock;import java.io.UnsupportedEncodingException;import javax.crypto.Cipher;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;/** * @author Jackie * */public class TripleDESAlgorithm {    private static final String ALGORITHM = "DESede";    public static byte[] encrypt(String cryptKey, byte[] src) {        try {            SecretKey deskey = new SecretKeySpec(build3DesKey(cryptKey), ALGORITHM);            Cipher c1 = Cipher.getInstance(ALGORITHM);            c1.init(Cipher.ENCRYPT_MODE, deskey);            return c1.doFinal(src);        } catch (Exception e) {            e.printStackTrace();        }        return null;    }    public static byte[] decrypt(String cryptKey, byte[] src) {        try {            SecretKey deskey = new SecretKeySpec(build3DesKey(cryptKey), ALGORITHM);            Cipher c1 = Cipher.getInstance(ALGORITHM);            c1.init(Cipher.DECRYPT_MODE, deskey);            return c1.doFinal(src);        } catch (Exception e) {            e.printStackTrace();        }        return null;    }    static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException {        byte[] key = new byte[24];        byte[] temp = keyStr.getBytes("UTF-8");        if (key.length > temp.length) {            System.arraycopy(temp, 0, key, 0, temp.length);        } else {            System.arraycopy(temp, 0, key, 0, key.length);        }        return key;    }}

用来验证这个算法类的单元测试代码工作正常,运行结果显示上述加密、解密代码逻辑正确,没有错误,测试代码如下。

 

 

package org.jackie.study.powermock;import org.junit.Assert;import org.junit.Test;public class TripleDESAlgorithmTest {    @Test    public void test() throws Exception {        String key = String.valueOf(System.currentTimeMillis()) + "jackie";        byte[] encrypted = TripleDESAlgorithm.encrypt(key, "helloworld".getBytes("UTF-8"));        byte[] decrypted = TripleDESAlgorithm.decrypt(key, encrypted);        Assert.assertEquals("helloworld", new String(decrypted, "UTF-8"));    }}

但当我使用单元测试代码来验证特性代码功能是否正常时,但恼人的事情发生了,测试代码抛出了诡异的异常,如下。

 

 

java.lang.ClassCastException: com.sun.crypto.provider.DESedeCipher cannot be cast to javax.crypto.CipherSpi	at javax.crypto.Cipher.chooseProvider(Cipher.java:845)	at javax.crypto.Cipher.init(Cipher.java:1213)	at javax.crypto.Cipher.init(Cipher.java:1153)	at org.jackie.study.powermock.TripleDESAlgorithm.encrypt(TripleDESAlgorithm.java:23)	at org.jackie.study.powermock.SubscriberTest.testSayHello(SubscriberTest.java:19)	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)	at java.lang.reflect.Method.invoke(Method.java:601)	at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)	at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)

异常信息比较长,这里仅截取了一部分,但是可以说明问题。

 

业务代码和测试代码如下。

 

// 业务代码package org.jackie.study.powermock;public class Subscriber {    private String name;    // 解密收到的加密信息    public String sayHello(String name, byte[] message) throws Exception    {        byte[] realMessage = TripleDESAlgorithm.decrypt(name, message);                if (realMessage != null)        {            this.name = name;            return new String(realMessage, "UTF-8");        }        return null;    }    public String getName() {        return name;    }}// 测试代码package org.jackie.study.powermock;import org.junit.Assert;import org.junit.Test;import org.junit.runner.RunWith;import org.powermock.core.classloader.annotations.PrepareForTest;import org.powermock.modules.junit4.PowerMockRunner;@RunWith(PowerMockRunner.class)@PrepareForTestpublic class SubscriberTest {	@Test	public void testSayHello() throws Exception {	    byte[] encryptMessage = TripleDESAlgorithm.encrypt("jackie", "hello world!".getBytes("UTF-8"));	    	    Subscriber subscriber = new Subscriber();	    subscriber.sayHello("jackie", encryptMessage);	    Assert.assertEquals("jackie", subscriber.getName());	}}

异常很让人伤脑筋,因为反编译类com.sun.crypto.provider.DESedeCipher可以发现,这个算法实现类的确是javax.crypto.CipherSpi的子类,类转换失败实在是不应该。通常情况下如果出现ClassCastException,除了确实是类型不匹配外,还有一种可能即是两个类的ClassLoader不同,导致JVM认为这两个类没有关联。想到这里,这个问题基本上就有点思路了,因为PowerMock的工作原理即是使用自定义的类加载器来加载被修改过的类,从而达到打桩的目的,这里会不会是这个原因呢?

求助Google大师,发现在官网上有如下一段话。根据提示,我在测试类SubscriberTest前面加上了@PowerMockIgnore({"javax.crypto.*"}),保存之后重新运行测试代码,发现异常不再抛出,问题得到了解决。

The reason is that the XML framework tries to instantiate classes using reflection and does this from the thread context classloader (PowerMock's classloader) but then tries to assign the created object to a field not loaded by the same classloader. When this happens you need to make use of the @PowerMockIgnore annotation to tell PowerMock to defer the loading of a certain package to the system classloader. What you need to ignore is case specific but usually it's the XML framework or some packages that interact with it. E.g. @PowerMockIgnore({"org.xml.*", "javax.xml.*"}).

从上述描述中可以得到的信息是,假如待测试类中使用到了XML解析相关的包和类,那么测试类前同样需要增加@PowerMockIgnore({"org.xml.*", "javax.xml.*"}),消除类加载器引入的ClassCastException。

 

转载于:https://www.cnblogs.com/pangblog/p/3255877.html

你可能感兴趣的文章
jquery 编程的最佳实践
查看>>
MeetMe
查看>>
IP报文格式及各字段意义
查看>>
(转载)rabbitmq与springboot的安装与集成
查看>>
C2. Power Transmission (Hard Edition)(线段相交)
查看>>
STM32F0使用LL库实现SHT70通讯
查看>>
Atitit. Xss 漏洞的原理and应用xss木马
查看>>
MySQL源码 数据结构array
查看>>
(文件过多时)删除目录下全部文件
查看>>
T-SQL函数总结
查看>>
python 序列:列表
查看>>
web移动端
查看>>
pythonchallenge闯关 第13题
查看>>
linux上很方便的上传下载文件工具rz和sz使用介绍
查看>>
React之特点及常见用法
查看>>
【WEB前端经验之谈】时间一年半,或沉淀、或从零开始。
查看>>
优云软件助阵GOPS·2017全球运维大会北京站
查看>>
linux 装mysql的方法和步骤
查看>>
poj3667(线段树区间合并&区间查询)
查看>>
51nod1241(连续上升子序列)
查看>>