完成事件代理类及单元测试

This commit is contained in:
彭宇琦 2020-07-12 14:25:50 +08:00
parent eb427a1b61
commit 95790ae4d9
5 changed files with 256 additions and 71 deletions

View File

@ -47,4 +47,12 @@ public abstract class AbstractEvent {
public void setWaitTime(long waitTime) {
wait.withTimeout(Duration.ofSeconds(waitTime));
}
/**
* 用于返回存储的{@link WebDriver}类对象
* @return{@link WebDriver}类对象
*/
public WebDriver getDriver() {
return driver;
}
}

View File

@ -41,7 +41,7 @@ public class EventInformation {
this.method = method;
this.args = args;
//提取Element类对象
getElement();
toElement();
}
/**
@ -60,10 +60,18 @@ public class EventInformation {
return args;
}
/**
* 用于返回传入到方法中{@link Element}类对象集合
* @return {@link Element}类对象集合
*/
public ArrayList<Element> getElement() {
return elementList;
}
/**
* 用于将args中为Element类对象的参数进行转换并存储至elementList中
*/
private void getElement() {
private void toElement() {
Arrays.stream(args).forEach(arg -> {
if (arg instanceof Element) {
elementList.add((Element) arg);

View File

@ -6,12 +6,52 @@ import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.regex.Pattern;
import org.openqa.selenium.WebDriver;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import pres.auxiliary.work.selenium.brower.ChromeBrower;
import pres.auxiliary.work.selenium.element.Element;
/**
* <p><b>文件名</b>EventProxy.java</p>
* <p><b>用途</b>
* 用于对事件类进行代理使其能在对应的事件方法执行前后能执行指定方法以增强事件的执行
* 类中提供6种增强方法的方式其名称与执行顺序为方法前置通知元素前置通知方法成功/失败通知两种
* 元素后置通知方法最终通知解释如下
* <ol>
* <li>方法前置通知根据方法名匹配到相应的方法后在执行事件前执行的方法</li>
* <li>元素前置通知根据元素名称匹配到传入方法的元素后在执行事件前执行的方法</li>
* <li>方法成功通知根据方法名匹配到相应的方法后在事件成功执行未抛出异常后执行的方法</li>
* <li>方法失败通知根据方法名匹配到相应的方法后在事件失败执行抛出异常后执行的方法</li>
* <li>元素后置通知根据元素名称匹配到传入方法的元素后在执行事件后无论是否抛出异常执行的方法</li>
* <li>方法最终通知根据方法名匹配到相应的方法后在执行事件后无论是否抛出异常执行的方法</li>
* </ol>
* 可参考以下示例
* <p>
* 假设存在元素xpah:元素1//*[text()='登录']元素2//*[@name='account']元素3//*[@name='password']
* 在点击元素1前需要先在元素2和元素3中分别输入admin123456并且在此前定义了{@link ChromeBrower}浏览器对象变量名为
* chrome此时可以将代码写作<br>
* <pre>{@code
* EventProxy<ClickEvent> clickEventProxy = new EventProxy(new ClickEvent(chrome.getDriver()));
*
* clickProxy.addAcion(ActionType.ELEMENT_BEFORE, ".*登录.*", (info) -> {
* TextEvent text = inputProxy.getProxyInstance();
* text.input(by.getElement("//*[@name='account']"), "admin");
* text.input(by.getElement("//*[@name='password']"), "1111111");
* });
* clickEventProxy.getProxyInstance().click(new CommnBy(chrome).getElement("//*[text()='登录']"));
*
* </pre>
* </p>
* </p>
* <p><b>编码时间</b>2020年7月12日 下午1:35:22</p>
* <p><b>修改时间</b>2020年7月12日 下午1:35:22</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*/
public class EventProxy<T extends AbstractEvent> implements MethodInterceptor {
/**
* 用于存储方法前置通知key表示方法名称匹配规则value表示调用的方法
@ -42,6 +82,7 @@ public class EventProxy<T extends AbstractEvent> implements MethodInterceptor {
* 事件类对象
*/
private T target;
private WebDriver driver;
/**
* 构造代理类
@ -49,6 +90,7 @@ public class EventProxy<T extends AbstractEvent> implements MethodInterceptor {
*/
public EventProxy(T target) {
this.target = target;
driver = ((AbstractEvent) target).getDriver();
}
/**
@ -58,14 +100,53 @@ public class EventProxy<T extends AbstractEvent> implements MethodInterceptor {
*/
@SuppressWarnings("unchecked")
public T getProxyInstance(){
//1.工具类
//工具类
Enhancer en = new Enhancer();
//2.设置父类
//设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
//设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return (T) en.create();
//创建子类(代理对象)
return (T) en.create(new Class[] {WebDriver.class}, new Object[] {driver});
// return (T) en.create();
}
/**
* 根据相应的执行的方法类型添加指定的名称匹配规则及执行方法
* @param actionType 通知类型枚举类{@link ActionType}
* @param regex 名称匹配规则元素名称或者方法名称规则为正则表达式
* @param action 需要执行的方法
*/
public void addAcion(ActionType actionType, String regex, EventAction action) {
//指向需要添加通知的map
LinkedHashMap<String, ArrayList<EventAction>> actionMap = null;
//根据不同类型的通知将actionMap指向相应的map
switch (actionType) {
case FUNCTION_BEFORE:
actionMap = functionBeforeActionMap;
break;
case ELEMENT_BEFORE:
actionMap = elementBeforeActionMap;
break;
case FUNCTION_SUCCESS_AFTER:
actionMap = functionSuccessActionMap;
break;
case FUNCTION_FAIL_AFTER:
actionMap = functionFailActionMap;
break;
case ELEMENT_AFTER:
actionMap = elementAfterActionMap;
break;
case FUNCTION_FINAL:
actionMap = functionFinalActionMap;
break;
default:
break;
}
//执行添加通知的方法
mapAddAction(regex, action, actionMap);
}
@Override
@ -75,8 +156,38 @@ public class EventProxy<T extends AbstractEvent> implements MethodInterceptor {
//按照方法名或元素名匹配到相应的通知后运行通知若通知运行出现异常则直接跳过
//运行方法前置通知
functionBeforeActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(method.getName()).matches()) {
runFuntionAction(eventInformation, functionBeforeActionMap);
//运行元素前置通知
runElementAction(eventInformation, elementBeforeActionMap);
//执行目标对象的方法
try {
Object returnValue = method.invoke(target, args);
//运行方法成功执行通知
runFuntionAction(eventInformation, functionSuccessActionMap);
return returnValue;
} catch (Exception exception) {
//运行方法失败执行通知
runFuntionAction(eventInformation, functionFailActionMap);
throw exception;
} finally {
//运行元素后置通知
runElementAction(eventInformation, elementAfterActionMap);
//运行方法最终通知
runFuntionAction(eventInformation, functionFinalActionMap);
}
}
/**
* 运行方法通知
* @param eventInformation 事件信息类对象
* @param actionMap 需要执行的通知
*/
private void runFuntionAction(EventInformation eventInformation, LinkedHashMap<String, ArrayList<EventAction>> actionMap) {
actionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(eventInformation.getMethod().getName()).matches()) {
value.forEach(action -> {
//出现异常则不进行处理
try {
@ -86,10 +197,16 @@ public class EventProxy<T extends AbstractEvent> implements MethodInterceptor {
});
}
});
//运行元素前置通知
Arrays.stream(args).filter(arg -> arg instanceof Element).forEach(arg -> {
elementBeforeActionMap.forEach((key, value) -> {
}
/**
* 执行元素通知
* @param eventInformation 事件类对象
* @param actionMap 需要执行的通知
*/
private void runElementAction(EventInformation eventInformation, LinkedHashMap<String, ArrayList<EventAction>> actionMap) {
Arrays.stream(eventInformation.getParam()).filter(arg -> arg instanceof Element).forEach(arg -> {
actionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(((Element) arg).getName()).matches()) {
value.forEach(action -> {
try {
@ -100,64 +217,57 @@ public class EventProxy<T extends AbstractEvent> implements MethodInterceptor {
}
});
});
//执行目标对象的方法
try {
Object returnValue = method.invoke(target, args);
//运行方法成功执行通知
functionSuccessActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(method.getName()).matches()) {
value.forEach(action -> {
//出现异常则不进行处理
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
return returnValue;
} catch (Exception exception) {
//运行方法失败执行通知
functionFailActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(method.getName()).matches()) {
value.forEach(action -> {
//出现异常则不进行处理
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
throw exception;
} finally {
//运行元素后置通知
Arrays.stream(args).filter(arg -> arg instanceof Element).forEach(arg -> {
elementAfterActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(((Element) arg).getName()).matches()) {
value.forEach(action -> {
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
});
//运行方法最终通知
functionFinalActionMap.forEach((key, value) -> {
if (Pattern.compile(key).matcher(method.getName()).matches()) {
value.forEach(action -> {
//出现异常则不进行处理
try {
action.action(eventInformation);
} catch (Exception e) {
}
});
}
});
}
/**
* 用于向相应的通知map中添加通知
* @param regex 匹配规则
* @param action 通知
* @param actionMap 存储通知的map
*/
private void mapAddAction(String regex, EventAction action, LinkedHashMap<String, ArrayList<EventAction>> actionMap) {
//判断actionMap中是否存在regex若不存在则将regex加入到actionMap并构造ArrayList类
if (!actionMap.containsKey(regex)) {
actionMap.put(regex, new ArrayList<EventAction>());
}
//在相应的regex中添加action
actionMap.get(regex).add(action);
}
/**
* <p><b>文件名</b>EventProxy.java</p>
* <p><b>用途</b>用于标记通知的类型</p>
* <p><b>编码时间</b>2020年7月12日 上午11:24:57</p>
* <p><b>修改时间</b>2020年7月12日 上午11:24:57</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 8
*/
public enum ActionType {
/**
* 表示方法前置通知
*/
FUNCTION_BEFORE,
/**
* 表示元素前置通知
*/
ELEMENT_BEFORE,
/**
* 表示方法执行成功通知
*/
FUNCTION_SUCCESS_AFTER,
/**
* 表示方法执行失败通知
*/
FUNCTION_FAIL_AFTER,
/**
* 表示元素后置通知
*/
ELEMENT_AFTER,
/**
* 表示方法最终通知
*/
FUNCTION_FINAL;
}
}

View File

@ -0,0 +1,59 @@
package pres.auxiliary.work.selenium.event;
import java.io.File;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import pres.auxiliary.work.selenium.brower.ChromeBrower;
import pres.auxiliary.work.selenium.brower.ChromeBrower.ChromeOptionType;
import pres.auxiliary.work.selenium.element.CommonBy;
import pres.auxiliary.work.selenium.event.EventProxy.ActionType;
public class EventProxyTest {
EventProxy<ClickEvent> clickProxy;
EventProxy<TextEvent> inputProxy;
ChromeBrower chrome;
CommonBy by;
@BeforeClass
public void init() {
chrome = new ChromeBrower(new File("Resource/BrowersDriver/Chrom/83.0.4103.39/chromedriver.exe"));
chrome.addConfig(ChromeOptionType.CONTRAL_OPEN_BROWER, "127.0.0.1:9222");
clickProxy = new EventProxy<>(new ClickEvent(chrome.getDriver()));
inputProxy = new EventProxy<>(new TextEvent(chrome.getDriver()));
by = new CommonBy(chrome);
}
@AfterClass
public void showResult() {
ClickEvent click = clickProxy.getProxyInstance();
click.doubleClick(by.getElement("//*[text()='登录']"));
}
@Test
public void addAcionTest() {
TextEvent textEvent = new TextEvent(chrome.getDriver());
textEvent.input(by.getElement("//*[@name='account']"), "admin");
textEvent.input(by.getElement("//*[@name='password']"), "1111111");
inputProxy.addAcion(ActionType.FUNCTION_BEFORE, ".*input.*", (info) -> {
inputProxy.getProxyInstance().clear(info.getElement().get(0));
});
clickProxy.addAcion(ActionType.ELEMENT_BEFORE, ".*登录.*", (info) -> {
TextEvent text = inputProxy.getProxyInstance();
text.input(by.getElement("//*[@name='account']"), "admin");
text.input(by.getElement("//*[@name='password']"), "1111111");
});
clickProxy.addAcion(ActionType.ELEMENT_AFTER, ".*登录.*", (info) -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
by.alertAccept();
});
}
}