阿⾥java单元测试_阿⾥开源新⼀代单元测试Mock⼯具!
TestableMock是基于源码和字节码增强的Java单元测试辅助⼯具,包含以下功能:
访问被测类私有成员:使单元测试能直接调⽤和访问被测类的私有成员,解决私有成员初始化和私有⽅法测试的问题
快速Mock任意调⽤:使被测类的任意⽅法调⽤快速替换为Mock⽅法,实现"指哪换哪",解决传统Mock⼯具使⽤繁琐的问题
辅助测试void⽅法:利⽤Mock校验器对⽅法的内部逻辑进⾏检查,解决⽆返回值⽅法难以实施单元测试的问题访问私有成员字段和⽅法
如今关于私有⽅法是否应该做单元测试的争论正逐渐消停,开发者的普遍实践已经给出事实答案。通过公有⽅法间接测私有⽅法在很多情况下难以进⾏,开发者们更愿意通过修改⽅法可见性的办法来让原本私有的⽅法在测试⽤例中变得可测。
此外,在单元测试中时常会需要对被测对象进⾏特定的成员字段初始化,但有时由于被测类的构造⽅法限制,使得⽆法便捷的对这些字段进
⾏赋值。那么,能否在不破坏被测类型封装的情况下,允许单元测试⽤例内的代码直接访问被测类的私有⽅法和成员字段
呢?TestableMo英语小说 ck提供了两种简单的解决⽅案。⽅法⼀:使⽤`@EnablePrivateAccess`注解
只需为测试类添加@EnablePrivateAccess注解,即可在测试⽤例中获得以下增强能⼒:
调⽤被测类的私有⽅法(包括静态⽅法)
读取被测类的私有字段(包括静态字段)修改被测类的私有字段(包括静态字段)
修改被测类的常量字段(使⽤final修饰的字段,包括静态字段)
访问和修改私有、常量成员时,IDE可能会提⽰语法有误,但编译器将能够正常运⾏测试。(使⽤编译期代码增强,⽬前仅实现了Java语⾔的适配)
效果见java-demo⽰例项⽬DemoPrivateAccessTest测试类中的⽤例。⽅法⼆:使⽤`PrivateAccessor`⼯具类
若不希望看到IDE的语法错误提醒,或是在⾮Java语⾔的JVM⼯程(譬如Kotlin语⾔)⾥,也可以借助PrivateAccessor⼯具类来直接访问私有成员。
这个类提供了6个静态⽅法:
(被测对象,"私有字段名")➜读取被测类的私有字段
(被测对象,"私有字段名",新的值)➜修改被测类的私有字段(或常量字段)
(被测对象,"私有⽅法名",调⽤参数..)➜调⽤被测类的私有⽅法
tic(被测类型,"私有静态字段名")➜读取被测类的静态私有字段
tic(被测类型,"私有静态字段名",新的值)➜修改被测类的静态私有字段(或静态常量字段)
Static(被测类型,"私有静态⽅法名",调⽤参数..)➜调⽤被测类的静态私有⽅法快速Mock被测类的任意⽅法调⽤
相⽐以往Mock⼯具以类为粒度的Mock⽅式,Testab昭君出塞的故事简介 leMoc关于春天的诗句 k允许⽤户直接定义需要Mock的单个⽅法,并遵循约定优于配置的原则,按照
规则⾃动在测试运⾏时替换被测⽅法中的指定⽅法调⽤。归纳起来就两条:
Mock⾮构造⽅法,拷贝原⽅法定义到测试类,增加⼀个与调⽤者类型相同的参数,加@MockMethod注解Mock构造⽅法,拷贝原⽅法定义到测试类,返回值换成构造的类型,⽅法名随意,加@MockContructor注解
具体的Mock⽅法定义约定如下嘴角上火怎么办 :1.覆写任意类的⽅法调⽤
在测试类⾥定义⼀个有@MockMethod注解的普通⽅法,使它与需覆写的⽅法名称、参数、返回值类型完全⼀致,然后在其参数列表⾸位再增加⼀个类型为该⽅法原本所属对象类型的参数。
此时被测类中所有对该需覆写⽅法的调⽤,将在单元测试运⾏时,将⾃动被替换为对上述⾃定义Mock⽅法的调⽤。
注意:当遇到待覆写⽅法有重名时,可以将需覆写的⽅法名写到@MockMet党忠诚 hod注解的targetMethod参数⾥,这样Mock⽅法⾃⾝就可以随意命名了。
例如,被测类中有⼀处"anything".substring(1,2)调⽤,我们希望在运⾏测试的时候将它换成⼀个固定字符串,则只需在测试类定义如下⽅法:
//原⽅法签名为`Stringsubstring(int,int)`//调⽤此⽅法的对象`"anything"`类型为`String`
//则Mock⽅法签名在其参数列表⾸位增加⼀个类型为`String`的参数(名字随意)
//此参数可⽤于获得当时的实际调⽤者的值和上下⽂@MockMethod
privateStringsubstring(Stringlf,inti,intj){
return"sub_string";}
下⾯这个例⼦展⽰了targetMethod参数的⽤法,其效果与上述⽰例相同://使⽤`targetMethod`指定需Mock的⽅法名
//此⽅法本⾝现在可以随意命名,但⽅法参数依然需要遵循相同的匹配规则@MockMethod(targetMethod="substring")
privateStringu_any_mock_method_name(Stringlf,inti,intj){
return"sub_string";}
完整代码⽰例见java-demo和kotlin-demo⽰例项⽬中的should_able_to_mock_common_method()测试⽤例。(由于Kotlin对String类
型进⾏了魔改,故Kotlin⽰例中将被测⽅法在BlackBox类⾥加了⼀层封装)2.覆写被测类⾃⾝的成员⽅法
有时候,在对某些⽅法进⾏测试时,希望将被测类⾃⾝的另外⼀些成员⽅法Mock掉。
操作⽅法与前⼀种情况相同,Mock⽅法的第⼀个参数类型需怎么画独角兽 与被测类相同,即可实现对被测类⾃⾝(不论是公有或私有)成员⽅法的覆写。
例如,被测类中有⼀个签名为StringinnerFunc(String)的私有⽅法,我们希望在测试的时候将它替换掉,则只需在测试类定义如下⽅法://被测类型是`DemoMock`
//因此在定义Mock⽅法时,在⽬标⽅法参数⾸位加⼀个类型为`DemoMock`的参数(名字随意)@MockMethod
privateStringinnerFunc(DemoMocklf,Stringtext){return"mock_"+text;
}
3.覆写任意类的静态⽅法
对于静牛胸肉怎么做好吃 态⽅法的Mock与普通⽅法相同。但需要注意的是,静态⽅法的Mock⽅法被调⽤时,传⼊的第⼀个参数实际值始终是null。
例如,在被测类中调⽤了BlackBox类型中的静态⽅法cretBox(),改⽅法签名为BlackBoxcretBox(),则Mock⽅法如下://⽬标静态⽅法定义在`BlackBox`类型中
//在定义Mock⽅法时,在⽬标⽅法参数⾸位加⼀个类型为`BlackBox`的参数(名字随意)
//此参数仅⽤于标识⽬标类型,实际传⼊值将始终为`null`@MockMethod
privateBlackBoxcretBox(BlackBoxignore){
returnnewBlackBox("not_cret_box");}
完整代码⽰例见java-demo和kotlin-demo⽰例项⽬中的should_able_to_mock_static_method()测试⽤例。测试⽆返回值的⽅法
如何对void类型的⽅法进⾏测试⼀直是许多单元测试框架在悄悄回避的话题,由于以往的单元测试⼿段主要是对被测单元的返回结果进⾏校验,当遇到⽅法没有返回值时就会变得⽆从跑的成语 下⼿。
从功能的⾓度来说,虽然void⽅法不返回任何值,但它的执⾏⼀定会对外界产⽣某些潜在影响,我们将其称为⽅法的"副作⽤",⽐如:
初始化某些外部变量(私有成员变量或者全局静态变量)
在⽅法体内对外部对象实例进⾏赋值
输出了⽇志
调⽤了其他外部⽅法……
不返回任何值也不产⽣任何"副作⽤"的⽅法没有存在的意义。
这些"副作⽤"的本质归纳来说可分为两类:修改外部变量和调⽤外部⽅法。
通过TestableMock的私有字段访问和Mock校验器可以很⽅便的实现对"副作⽤"的结果检查。1.修改外部变上网记录查询 量的void⽅法
例如,下⾯这个⽅法会根据输⼊修改私有成员变量hashCache:classDemo{
privateMaphashCache=mapOf();
publicvoidupdateCache(Stringdomain,Stringkey){
StringcacheKey=domain+"::"+key;Integernum=(cacheKey);
(cacheKey,count==null?initHash(key):nextHash(num,key));}
...//其他⽅法省略
}
若要测试此⽅法,可以利⽤TestableMock直接读取私有成员变量的值,对结果进⾏校验:
@EnablePrivateAccess//启⽤TestableMock的私有成员访问功能classDemoTest{
privateDemodemo=newDemo();@Test
publicvoidtestSaveToCache(){
IntegerfirstVal=sh("hello");//访问私有⽅法
IntegernextVal=sh(firstVal,"hello");//访问私有⽅法Cache("demo","hello");
asrtEquals(firstVal,("demo::hello"));//读取私有变量Cache("demo","hello");
asrtEquals(nextVal,("demo::hello"));//读取私有变量
}}
2.调⽤外部⽅法的void⽅法
例如,下⾯这个⽅法会根据输⼊打印信息到控制台:classDemo{
publicvoidrecordAction(Actionaction){
SimpleDateFormatdf=newSimpleDateFormat("yyyy-MM-ddhh:mm:ss");StringtimeStamp=(newDate());
n(timeStamp+"["+e()+"]"+get());
}}
若要测试此⽅法,可以利⽤TestableMock快速Mock掉n⽅法。在Mock⽅法体⾥可以继续执⾏原调⽤(相当于并不影响本来⽅法功能,仅⽤于做调⽤记录),也可以直接留空(相当于去除了原⽅法的副作⽤)。
在执⾏完被测的void类型⽅法以后,⽤()校验传⼊的打印内容是否符合预期:classDemoTest{
privateDemodemo=newDemo();
//拦截`n`调⽤@MockMethod
publicvoidprintln(PrintStreamps,Stringmsg){
//执⾏原调⽤n(msg);
}@Test
publicvoidtestRecordAction(){
Actionaction=newAction("click",":download");Action();
//验证Mock⽅法`println`被调⽤,且传⼊参数符合预期
verify("println").with(matches("d{4}-d{2}-d{2}d{2}:d{2}:d{2}[click]:download"));
}
}
项⽬地址推荐阅读:
本文发布于:2023-04-14 01:15:05,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/fan/89/830653.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |