異步校驗工具awaitility快速入門
1.背景
在編寫自動化測試用例過程中,往往會遇見被測代碼有異步或者隊列處理的中間過程;如果需要校驗這部分結果,必須等待異步操作結束或隊列消費完,而這個中間等待的時間是不確定的,常常是根據經驗值設定,通過 Thread.sleep(經驗值) ,而這個時間通常會設置成最長的那次時間,但是可能99%次這個異步操作都低于這個最長的時間,這就造成了每次執行這個測試用例都花費了異步任務最長的那次時間。
現介紹一款開源工具awaitility: https://github.com/awaitility/awaitility ,該工具提供輪詢的方式,判斷操作是否完成,以最短的時間獲取異步任務結果。
2.入門
awaitility支持Java、Scala、Groovy,本文以Java介紹。
maven工程在pom.xml添加awaitility依賴:
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
3.實例
測試類import相關Class:
import java.util.concurrent.Callable;
import static java.util.concurrent.TimeUnit.*;
import static org.awaitility.Awaitility.;
import static org.awaitility.Duration.;
import static org.awaitility.pollinterval.FibonacciPollInterval.*;</code></pre>
構造一個異步任務:
interface CounterService extends Runnable {
int getCount();
}
// 每隔1s, count累加1
class CounterServiceImpl implements CounterService {
private volatile int count = 0;
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;
}
}
3-1.默認等待時間
await().until(Callable conditionEvaluator)最多等待10s直到conditionEvaluator滿足條件,否則ConditionTimeoutException。
@Test
public void testAsynchronousNormal(){
final CounterService service = new CounterServiceImpl();
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());
}
}
默認超時時間為10s, 可通過setDefaultTimeout()自定義默認超時時間。
3-2.最多等待
await().atMost() 設置最多等待時間,如果在這時間內條件還不滿足,將拋出ConditionTimeoutException。
@Test
public void testAsynchronousAtMost(){
final CounterService service = new CounterServiceImpl();
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());
}
}
3-3.至少等待
await().atLeast() 設置至少等待時間;多個條件時候用and()連接。
@Test
public void testAsynchronousAtLeast(){
final CounterService service = new CounterServiceImpl();
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());
}
}</code></pre>
3-4.forever等待
forever等待,不推薦使用,可能導致死循環。
await().forever().until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return service.getCount() == 6;
}
});
3-5.輪詢
with().pollInterval(ONE_HUNDRED_MILLISECONDS).and().with().pollDelay(50, MILLISECONDS) that is conditions are checked after 50ms then 50ms+100ms。
@Test
public void testAsynchronousPoll(){
final CounterService service = new CounterServiceImpl();
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());
}
}
3-6.Fibonacci輪詢
with().pollInterval(fibonacci(SECONDS))非線性輪詢,按照fibonacci數輪詢。
@Test
public void testAsynchronousFibonacciPoll(){
final CounterService service = new CounterServiceImpl();
service.run();
try{
// 使用fibonacci數作為間隔數1,1,2,3,5,8,..., 默認單位milliseconds with().pollInterval(fibonacci(SECONDS)).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());
}
}
來自:http://blog.csdn.net/neven7/article/details/55004939