1,jmockit
在Maven pom.xml配置
1 2 3 4 5 6 |
|
JUnit4.x及以下用户特别注意事项
如果你是通过mvn test来运行你的测试程序 , 请确保JMockit的依赖定义出现在JUnit的依赖之前。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Jmockit 有两种mock的方式:
1. Behavior-oriented(Expectations & Verifications)
2. State-oriented(MockUp)
Behavior-oriented是基于行为的mock,对mock目标代码的行为进行模仿,更像黑盒测试。State-oriented 是基于状态的mock,是站在目标测试代码内部的。可以对传入的参数进行检查、匹配,才返回某些结果,类似白盒。而State-oriented的 new MockUp基本上可以mock任何代码或逻辑。非常强大。
Jmockit可以mock的种类包含了:
1. class(abstract, final, static)
2. interface
3. enum
4. annotation
5. native
jmockit基本有三个步骤:
(1)打桩。指定要打桩类和函数,模拟返回结果。这里是new Mockup(NegativeTransDos)。
(2)调用被测方法。被测逻辑执行过程中,之前的打桩数据生效。
(3)判断测试结果是否符合预期。
通过以下方法来模拟类和方法。
new Mockup(类) {
模拟方法{
控制该方法返回结果
}
}
JMockit的程序结构
包含了测试属性或测试参数,测试方法,测试方法体中又包含录制代码块,重放测试逻辑,验证代码块。
//JMockit的程序结构
public class ProgramConstructureTest {
// 这是一个测试属性
@Mocked
HelloJMockit helloJMockit;
@Test
public void test1() {
// 录制(Record)
new Expectations() {
{
helloJMockit.sayHello();
// 期待上述调用的返回是"hello,david",而不是返回"hello,JMockit"
result = "hello,david";
}
};
// 重放(Replay)
String msg = helloJMockit.sayHello();
Assert.assertTrue(msg.equals("hello,david"));
// 验证(Verification)
new Verifications() {
{
helloJMockit.sayHello();
times = 1;
}
};
}
@Test
public void test2(@Mocked HelloJMockit helloJMockit /* 这是一个测试参数 */) {
// 录制(Record)
new Expectations() {
{
helloJMockit.sayHello();
// 期待上述调用的返回是"hello,david",而不是返回"hello,JMockit"
result = "hello,david";
}
};
// 重放(Replay)
String msg = helloJMockit.sayHello();
Assert.assertTrue(msg.equals("hello,david"));
// 验证(Verification)
new Verifications() {
{
helloJMockit.sayHello();
// 验证helloJMockit.sayHello()这个方法调用了1次
times = 1;
}
};
}
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
@Injectable 也是告诉 JMockit生成一个Mocked对象,但@Injectable只是针对其修饰的实例,而@Mocked是针对其修饰类的所有实例。
此外,@Injectable对类的静态方法,构造函数没有影响。因为它只影响某一个实例嘛!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
假设现在我们需要测试OrderService类的submitOrder方法,可是OrderService依赖MailService,UserCheckService类,
在测试过程中,我们并不想真正连结邮件服务器,也不想连结校验用户身份的服务器校验用户身份,怎么办呢?
此时@Tested与@Injectable就排上用场了!请看下面的测试程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
-
@Injectable 与 @Mocked的不同
-
@Tested & @Injectable 两个好基友,通常搭配使用
为便于演示,我们以电商网站下订单的场景为例:在买家下订单时,电商网站后台程序需要校验买家的身份(是否合法,例如是否在黑名单中),
若下订单没有问题还要发邮件给买家。 相信下面的代码,你一定能看明白 。 -
@Tested & @Injectable功能总结
@Injectable 也表示一个Mocked对象,相比@Mocked,只不过只影响类的一个实例。而@Mocked默认是影响类的所有实例。
@Tested表示被测试对象。如果该对象没有赋值,JMockit会去实例化它,若@Tested的构造函数有参数,
则JMockit通过在测试属性&测试参数中查找@Injectable修饰的Mocked对象注入@Tested对象的构造函数来实例化,
不然,则用无参构造函数来实例化。除了构造函数的注入,JMockit还会通过属性查找的方式,把@Injectable对象注入到@Tested对象中。
注入的匹配规则:先类型,再名称(构造函数参数名,类的属性名)。若找到多个可以注入的@Injectable,则选择最优先定义的@Injectable对象。
当然,我们的测试程序要尽量避免这种情况出现。因为给哪个测试属性/测试参数加@Injectable,是人为控制的。
-
什么测试场景,我们要使用@Tested & @Injectable
显然,当我们需要手工管理被测试类的依赖时,就需要用到@Tested & @Injectable。
两者搭配起来用,JMockit就能帮我们轻松搞定被测试类及其依赖注入细节。