测试的分类
分类 | 功能 |
---|---|
单元测试 | 确保类,模块功能正确 |
集成测试 | 确保组件间接口,交互和链路正确 |
组件测试 | 确保微服务作为独立整体,接口功能正确 |
契约测试 | 确保服务提供方和消费方都遵守契约规范 |
端到端测试 | 确保整个应用满足用户需求 |
测试金字塔

一些测试工具
Hamcrest
使用过Junit 的应该有过体验:在实际开发中,一些基本的断言,如eqaul,null,true它们的可读性并不是很好。而且很多时候我们要比较对象、集合、Map等数据结构。这样我们要么进行大段的字段获取再断言。或者干脆自己编写表达式并断言其结果。
JUnit4.4引入了Hamcrest框架,Hamcest提供了一套匹配符Matcher,这些匹配符更接近自然语言,可读性高,更加灵活。
Hamcrest 提供了大量被称为“匹配器”的方法。其中每个匹配器都设计用于执行特定的比较操作。Hamcrest的可扩展性很好,让你能够创建自定义的匹配器。最重要的是,JUnit也包含了Hamcrest的核心,提供了对Hamcrest的原生支持,可以直接使用Hamcrest。当然要使用功能齐备的Hamcrest,还是要引入对它的依赖。
Hamcrest匹配器
核心:
anything - 总是匹配,如果你不关心测试下的对象是什么是有用的
describedAs - 添加一个定制的失败表述装饰器
is - 改进可读性装饰器 - 见下 “Sugar”
逻辑:
allOf - 如果所有匹配器都匹配才匹配,像Java里的&&
anyOf - 如果任何匹配器匹配就匹配,像Java里的||
not - 如果包装的匹配器不匹配器时匹配,反之亦然
对象:
equalTo - 测试对象相等使用Object.equals方法
hasToString - 测试Object.toString方法
instanceOf, isCompatibleType - 测试类型
notNullValue, nullValue - 测试null
sameInstance - 测试对象实例
Beans:
hasProperty - 测试JavaBeans属性
集合:
array - 测试一个数组元素test an array’s elements against an array of matchers
hasEntry, hasKey, hasValue - 测试一个Map包含一个实体,键或者值
hasItem, hasItems - 测试一个集合包含一个元素
hasItemInArray - 测试一个数组包含一个元素
数字:
closeTo - 测试浮点值接近给定的值
greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo - 测试次序
文本:
equalToIgnoringCase - 测试字符串相等忽略大小写
equalToIgnoringWhiteSpace - 测试字符串忽略空白
containsString, endsWith, startsWith - 测试字符串匹配
这些API 几乎覆盖了我们测试断言的所有情况。再提供良好阅读性的情况下,减少了一些取值、循环、类型判断等代码的编写。
异步代码测试工具awaitility
在被测代码有异步或者队列处理的中间过程时;如果需要校验这部分结果,必须等待异步操作结束或队列消费完,而这个中间等待的时间是不确定的,常常是根据经验值设定,通过Thread.sleep(经验值),而这个时间通常会设置成最长的那次时间,但是可能99%次这个异步操作都低于这个最长的时间,这就造成了每次执行这个测试用例都花费了异步任务最长的那次时间。
而awaitility提供轮询的方式,判断操作是否完成,以最短的时间获取异步任务结果。
如
@Test
public void updatesCustomerStatus() throws Exception {
// Publish an asynchronous event:
publishEvent(updateCustomerStatusEvent);
// Awaitility lets you wait until the asynchronous operation completes:
await().atMost(5, SECONDS).until(customerStatusIsUpdated());
}
CounterService.java异步类
public class CounterService implements Runnable {
private volatile int count = 0;
@Override
public void run() {
new Thread(new Runnable() {
@Override
public void run() {
try {
for(int index = 0; index < 5; index++) {
Thread.sleep(1000);
count += 1;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
}
public int getCount() {
return count;
}
}
CounterServiceTest.java测试类
import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.Callable;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.awaitility.Awaitility.await;
import static org.awaitility.Awaitility.with;
import static org.awaitility.Duration.ONE_HUNDRED_MILLISECONDS;
public class CounterServiceTest {
/**
* 默认等待时间
*/
@Test
public void asynchronousNormalTest(){
final CounterService service = new CounterService();
service.run();
try{
// 默认10s, 如果在这时间段内,条件依然不满足,将抛出ConditionTimeoutException
await().until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return service.getCount() == 5;
}
});
} catch (Exception e) {
Assert.fail("测试代码运行异常:" + e.getMessage() + ",代码位置:" + e.getStackTrace()[0].toString());
}
}
/**
* 最多等待
*/
@Test
public void asynchronousAtMostTest(){
final CounterService service = new CounterService();
service.run();
try{
// 指定超时时间3s, 如果在这时间段内,条件依然不满足,将抛出ConditionTimeoutException
await().atMost(3, SECONDS).until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return service.getCount() == 5;
}
});
} catch (Exception e) {
Assert.fail("测试代码运行异常:" + e.getMessage() + ",代码位置:" + e.getStackTrace()[0].toString());
}
}
/**
* 最少等待
*/
@Test
public void asynchronousAtLeastTest(){
final CounterService service = new CounterService();
service.run();
try{
// 指定至少1s, 最多3s, 如果在这时间段内,条件依然不满足,将抛出ConditionTimeoutException
await().atLeast(1, SECONDS).and().atMost(3, SECONDS).until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return service.getCount() == 2;
}
});
} catch (Exception e) {
Assert.fail("测试代码运行异常:" + e.getMessage() + ",代码位置:" + e.getStackTrace()[0].toString());
}
}
/**
* 轮询
*/
@Test
public void testAsynchronousPoll(){
final CounterService service = new CounterService();
service.run();
try{
// 轮询查询,pollInterval每隔多少时间段轮询, pollDelay每次轮询间隔时间
with().pollInterval(ONE_HUNDRED_MILLISECONDS).and().with().pollDelay(50, MILLISECONDS).await("count is greater 3").until(
new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return service.getCount() == 4;
}
});
} catch (Exception e) {
Assert.fail("测试代码运行异常:" + e.getMessage() + ",代码位置:" + e.getStackTrace()[0].toString());
}
}
}
网友评论