“哎吆,怎么這么多執(zhí)行失敗呢鹊汛?”,當(dāng)你看到自動化測試報告中低滩,尤其是ui自動化測試報告中顽冶,大面積執(zhí)行失敗欺抗,并且最后顯示的原因均是頁面元素timeout exception的時候,是不是覺得一個腦袋兩個大强重,雖然我們已經(jīng)加了等待時間绞呈,無論是隱式等待還是顯示等待,也不能完全解決該類問題间景!那有沒有啥好的方法來解決這個問題报强,以便提高自動化測試的穩(wěn)定性呢?
哈哈拱燃,答案是肯定的秉溉,那就是我們今天的主題,自動重試實(shí)現(xiàn)方法--AOP模式碗誉。相信有些老鐵會問了:什么是aop召嘶,我們當(dāng)如何去自動重試呢?AOP為Aspect Oriented Programming的縮寫,是面向切面編程,通過預(yù)編譯方式和運(yùn)行其動態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)哮缺。今天我們以百度搜索首頁為例弄跌,來詳細(xì)給大家分享-aop模式的應(yīng)用。
? ? ? 接著簡單給大家介紹一下自動化case的場景:進(jìn)入百度首頁尝苇,在搜索框內(nèi)輸入要搜索的關(guān)鍵字铛只,并點(diǎn)擊搜索按鈕。這里包含了百度首頁頁面的兩個元素糠溜,搜索輸入框和搜索按鈕淳玩。假設(shè)搜索輸入框元素一直加載不出來,我們要對整個輸入關(guān)鍵字的動作進(jìn)行重試非竿。而整個輸入關(guān)鍵字的動作是一個方法蜕着,如下:
public void sendKeysForSearchInput(String content){
searchInput.waitForPresent();
searchInput.clear();
searchInput.sendKeys(content);
}
那么如何來通過aop來實(shí)現(xiàn)我們的重試目標(biāo)呢?步驟如下:
首先红柱,要創(chuàng)建一個模板RetryTemplate類文件承匣,將要重試的次數(shù)蓖乘、重試的間隔時間和什么條件下重試定義于該模板中,以便后面的aop切面類中調(diào)用韧骗,具體的實(shí)現(xiàn)代碼如下嘉抒。
public abstract class RetryTemplate {
private static final int DEFAULT_RETRY_COUNT =0;
private int retryCount =DEFAULT_RETRY_COUNT;
// reset sleep time
private int sleepTime =0;
public int getSleepTime() {
return sleepTime;
}
public RetryTemplate setSleepTime(int sleepTime) {
if(sleepTime <0) {
throw new IllegalArgumentException("sleepTime shall be equal or bigger than 0");
}
this.sleepTime = sleepTime;
return this;
}
public int getRetryCount() {
return retryCount;
}
public RetryTemplate setRetryCount(int retryCount) {
if (retryCount <=0) {
throw new IllegalArgumentException("retryCount shall bigger than 0");
}
this.retryCount = retryCount;
return this;
}
/**
* retry for business,throw exception when fail;
* whether retry or not by returning status;
*
@return
*/
protected abstract Object toDo()throws Throwable;
public Object execute()throws InterruptedException {
for (int i =0; i <=retryCount; i++) {
try {
return toDo();
}catch (Throwable? e) {
System.out.println("run business:? "+ (i+1) +" times");
System.out.println("run business exception,e: "+e);
Thread.sleep(sleepTime);
}
}
return null;
}
}
其次袍暴,創(chuàng)建一個注解RetryFunction, 以便我們在需要重試的method中使用众眨。
具體代碼如下,其中定義了count和sleep參數(shù)容诬,count傳入method需要重試的次數(shù)娩梨,sleep傳入兩次重試的間隔時間。
import java.lang.annotation.*;
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RetryFunction {
/**
* retryCount
? ? * @return
? ? */
? ? int count()default 0;
/**
* retry interval Time
? ? * @return
? ? */
? ? int sleep()default 0;
}
然后览徒,也是我們最核心的一步狈定,定義我們的aop,即新建RetryAspect類文件习蓬。實(shí)現(xiàn)代碼如下:
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Slf4j
public class RetryAspect {
@Around(value ="@annotation(retryFunction)")
public Object execute(ProceedingJoinPoint joinPoint,RetryFunction retryFunction)throws Exception {
RetryTemplate retryTemplate =new RetryTemplate() {
@Override
? ? ? ? ? ? protected Object toDo()throws Throwable {
return joinPoint.proceed();
}
};
retryTemplate.setRetryCount(retryFunction.count()).setSleepTime(retryFunction.sleep());
return retryTemplate.execute();
}
}
是不是這樣就算結(jié)束了纽什,可以正常使用了呢,那肯定還是不行的躲叼,我們還需要配置aop.xml文件(base-package要配置正確芦缰,否則不能生效):
<?xml version="1.0" endcoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
? ? ? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
? ? ? xmlns:context="http://www.springframework.org/schema/context"
? ? ? xmlns:aop="http://www.springframework.org/schema/aop"
? ? ? xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="src.test.java"/>
<context:annotation-config/>
<aop:aspectj-autoproxy/>
</beans>
前面三步完成后,最后我們需要引用一下RetryFuction注解枫慷,看看實(shí)際的效果呢让蕾!回到文章開頭,介紹百度搜索首頁的輸入方法sendKeysForSearchInput或听。只需要在該方法上加上注解RetryFunction并配置想要重試的次數(shù)和時間即可探孝,如下:
@RetryFunction(count =1,sleep =2)
public void sendKeysForSearchInput(String content){
searchInput.waitForPresent();
searchInput.clear();
searchInput.sendKeys(content);
}
運(yùn)行的結(jié)果實(shí)際結(jié)果,如下圖所示誉裆,成功實(shí)現(xiàn)了sendKeysForSearchInput的重試顿颅。
最后,我們用實(shí)踐見識了aop的魅力足丢,為實(shí)現(xiàn)方法級別的重試粱腻,確實(shí)是不錯的解決方法。避免了強(qiáng)入侵業(yè)務(wù)代碼斩跌,方便方法自動重試绍些。