[<u>自动化测试</u>](javascript:;)框架结构说明
目前实现的自动化测试框架大致可以分为以下四块内容:
- 页面自动化测试
- [<u>API</u>](javascript:;)/WebService 自动化测试
- 工具类/support类
- 测试用例管理
页面自动化测试
页面自动化测试目前设计的目主要包括了如下几点: - 全部使用Page Object模式,进行测试数据和测试页面,测试流程分离
- 定制WebElement,可以控制元素的特殊处理,或者统一记录日志等
- 修改原生Selenium默认的Page Factory模式,转化为可以处理定制元素
- Driver Factory 根据配置生成driver
- 页面元素和测试的数据根据名字进行绑定
- 测试检查点可以注入到测试流程中
- 可以组装的测试步骤
-
可以通过注解定义页面测试步骤
页面自动化测试详细说明
修改后的Page Factory模式,流程图:
image.png
可以组装的测试步骤
可以组装的测试步骤的设计主要考虑以下几种组装方式:
- 多个页面测试的组装
- 过个业务流程测试的组装
- API和页面测试的组装
- 检查点可注入到组装了的流程中
- 实现不同子系统直接的调用
为了实现这个,主要定义了TestAction接口和TestActionsBuilder类,目的如下: - 所有的测试操作都实现TestAction接口的execute方法
- TestActionsBuilder 用来组装不同的TestAction,实现不同业务流程组装
页面元素和测试的数据根据名字进行绑定
目前的一个实现就是每一个页面完成之后,都有一个相应的数据模型和页面绑定,每一个数据元素和每一个可输入的页面元素相绑定,作为测试的输入; 同时简单实现了页面数据输入时不需要指定设置样的数据,由框架来根据输入数据来决定进行什么样的操作。 之后可以做一些优化,比如根据页面模型,已经一些固定数据,来自动化分生成测试数据。
注解驱动的页面流程组装
使用注解的方式在单个页面上构建测试流程,以达到一定程度的减少[<u>代码</u>](javascript:;)量,目前主要通过如下的注解: - UIActions
- UIAction
来驱动注解的测试
页面自动化实例-Login
新的页面测试方式引入一个概念是TestAction,这个怎么理解呢?可以认为是如下几个事物:
1、单个的一个测试动作,如点击某个按钮,访问某个连接
2、一连串的测试动作,可以在页面上点击一连串的按钮,填写很多表单
3、可以是操作读个页面,在每个页面上填写很多内容,点击很多按钮......
4、可以是一个API请求,也可以是多个API请求
5、可以是过个TestAction的组合
关于TestAction,在实际的时候过程中,只要实现TestAction接口就可以了,以下是TestAction接口目前的定义:
* 执行测试步骤的函数,可以是一个页面的多个步骤,可以是多个页面的步骤
*/ void execute(); /**
* test action 的名字,默认是TestAction class的名字
* @return */ default String getTestActionName(){ return this.getClass().getSimpleName();
}
Login 实现Test Action的不同方式
目前可以有两种方式来实现Login这个的TestAction,相信在以后的使用过程中可能这两种种方式都有可能会用到:
- 完全写代码实现,和之前代码没有太多区别,唯一的区别是元素定位内容不会在TestAction代码中出现了完全,从而实现了和页面元素的解耦
- 使用Annonation 来实现测试步骤
实现例子
代码实现可以分为三步: - 构建page
- 构建和业务相关的TestAction
- 构建测试类
构建Page 类
public class LoginPage extends BasePage { @FindBy(id= "usercode") private InputBox userCode; @FindBy(id="password") private InputBox password;
@FindBy(id="msg") private WebElement msg;
...... 省略 get set 方法
}
构建TestAction
继承BaseWebTestAction
public class LoginActionByHand extends BaseWebTestAction { public LoginActionByHand(WebDriver driver, TestData testData) { super(driver, testData);
} @Override public void execute() { //完全手动写TestAction LoginPage page = HtmlElementsLoader.createPageObject(driver,LoginPage.class);
page.getUserCode().input(testData.get("userCode")); //or convert the test data to a model to get the value page.getPassword().input(testData.get("password"));
page.getSubmit();
}
}
还有一种方式来些TestAction就是: 使用TestActionBuilder来写,可以给Builder添加多个TestAction,这个主要是组合多个TestAction使用的
public class LoginActionSuperExecutor extends BaseWebTestAction {
public LoginActionSuperExecutor(WebDriver driver, TestData testData) {
super(driver, testData);
}
@Override public void execute() {//使用ActionBuilder // build 可以添加多个TestAction, 这样就达到了组合不同Action的目的 TestActionsBuilder.build(new LoginActionByHand(driver,testData)).
addAfterActions(new TestAction() { // add AfterAction的意思就是可以在有些步骤后面添加一些特殊处理 @Override public void execute() {
driver.get("[http://gzz.dooioo.com/workspace](http://gzz.dooioo.com/workspace)");
}
}).execute(); // 也可以在最后自己写一些特殊处理 driver.get("[http://gzz.dooioo.com/workspace](http://gzz.dooioo.com/workspace)");
}
}
构建测试类
public class LoginFlowByExecutorTest extends BaseWebTest { User user = new User("110863","abcd1235"); @Test public void testLoginAction(){
LoginActionByHand flow1 = new LoginActionByHand(driver,user);
flow1.execute();
System.out.println("end of test");
} @Test public void testLoginAction_getTestActionName(){
Assert.assertEquals(new LoginFlowByExecutor(driver,user).getTestActionName(),"LoginFlowByExecutor");
}
}
注解方式来构建TestAction
在Page类上面添加注解,构建某个流程 格式如下例:
UIActions 表示有多个UIAction的注解,每一个UIAction就表示一个TestAction
每一个UIAction实际表示一个TestAction 下面这个例子中登陆,登陆2可以认为是两个不同的操作流程 elementActionDescription描述的是操作元素的动作,userCode input表示在元素userCode上面进行输入,输入什么,其实就是TestData中userCode的值 对于InputBox来说,动作input就是Inputbox的默认动作,所以在登陆2里面就省略了,所有省略动作的藐视都是用默认动作进行处理
```
@UIActions(
actions = { @UIAction(processName = "登陆",
elementActionDescription = {"userCode input","password input","submit click"}), @UIAction(processName = "登陆2",elementActionDescription = { "userCode","userCode ","submit " })
}
) public class LoginPageAnnotationWithUIAction extends BasePage { @FindBy(id= "usercode") private InputBox userCode; @FindBy(id="password") private InputBox password; @FindBy(id="msg") private HtmlElement msg; public Button getSubmit() { return submit;
} public void setSubmit(Button submit) { this.submit = submit;
} @FindBy(className = "btn_login") private Button submit;
。。。。。。。 省略get/set 方法
}
构建注解方式的TestAction
同样适用TestActionBuilder就可以了
public class LoginActionByExecuteUIAction extends BaseWebTestAction { public LoginActionByExecuteUIAction(WebDriver driver, TestData testData) { super(driver, testData);
} @Override public void execute() {
LoginPage page = LoginPage.createPage(LoginPage.class,driver);
AnnotationBasedActionBuilder.executeUIAction(page,"登陆",testData);
}
}
构建测试类
构建测试类的方式和上面构建测试类是其实是一样的
API/WebService 自动化测试
API(接口)数据驱动测试
API(接口)测试,这里主要是指http请求或者是指restful service类型的测试.主要的测试思路是根据API的规格 构造api的请求,然后向服务端发起请求,这样就可以得到服务端的请求返回值,进行验证。因此在整个测试过程 中如果构建这个请求是一个关键点,关于构建请求在前面介绍APITest的时候有提到过,可以参考 一下。但是一下的内容是在前文的基础上做了一些封装后,可以写少一点代码来实习API的数据驱动测试
如果你想学习软件测试的,我给你推荐个群:903217991,里面有从基础开始学习的软件测试学习视频讲解,还有大牛帮你解决疑惑。
API(接口)测试流程
在做了一些封装之后,api测试包括了以下几个步骤:
- 构建一个JSON文件来描述这个API的接口
- 构建一个调用这个API的java 类(构建请求)
- 构建和API规格说明相匹配的一个外部数据(excel)
- 构建测试用例类
构建JSON的API接口描述文件
以下是一个简单的json用来描述API,主要有以下几个字段: - queryParamters: 这个字段不是必须的,用来记录URL里面的可选参数,也就是在URL里面?之后的参数的
- pathParameters: 这个字段也不是一个必须要填写的,这个参数主要是用来记录URL中的参数在//之间的
- method:这个是必须要填写的,这是请求的方式,主要包括了get/post/delete/put等
- resourceURL:必须填写,用来标示请求资源的位置
- contentType:不是必须填写,如果请求的contentType是application/json,则可以不写,否则需要填写
- headers,不是必须填写,一般情况下可以不需要填写,因为默认的header值已经在工具类里设好了
- body: 如果请求没有body,可以不用填写,否则建议填写请求对应的JSON的类名(也不是必须要写的,目前框架还没有支持)
事实上一上内容大部分不是必须要填写的,但是还是建议可以填写完成,或许以后会用到。
{
"queryParameters":["userCode", "password" ],
"pathParameters":["ticketId","userId"],
"method":"POST",
"resourceURL":"/login",
"contentType":"application/x-www-form-urlencoded",
"headers":{"tokenId":"1234567432","Authorization":"890998776"} "body":"com.abcd.ddsf" }
构建一个调用API的JAVA类
以下是构建一个调用API的JAVA类的例子,需要做以下的事情: - 这个类需要继承BaseWebService - 起上一个和这个API做的事情相匹配的名字 - 指定描述那个API接口的JSON文件的路径 - 继承BaseWebService的构造函数
public class LoginAPI extends BaseWebService { private final static String loginAPIDescriptionPath = "servicedescription/loginapi.json"; public LoginAPI(RequestData data) { super(loginAPIDescriptionPath, data);
}
}
构建测试数据文件
测试数据还是使用外部excel的方式,他的格式基本可以固定,如下例:img
解释一下这个数据: RequestData.queryParameters(usercode), 表示queryParameter的一个key值是usercode,value就是用来进行数据驱动测试的值。
那么如果需要body的值呢,只要excel新增一列,列的第一行名字是RequestData.body就可以,如果是JSON格式的,就把真实的JSON这里就可以
如果是pathParameter,那么就是RequestData.pathParameters({key}表示你的pathParameter的名字
这个测试数据文件,需要放在Test的resource是目录里面,可以放在一个子目录里面。
构建测试用例
主要步骤包括: - 构建Dataprovider - 构建测试方法
@DataProvider(name="login_data") public Iterator getLoginData(Method m) throws InvocationTargetException, Exception, IOException {
Map clazzMap = new HashMap();
clazzMap.put("RequestData", RequestData.class); // build的参数就是所在测试数据文件的位置 Iterator y= ExcelHelper.build("testcase/login/loginapitest.xls").loadExcelDataToIterator(clazzMap); return y;
} @Test(dataProvider = "login_data") public void testLoginAPITes(RequestData data){
LoginAPI api = new LoginAPI(data);
api.execute(); //获取返回的类 System.out.println(api.getResponse()); //获取返回的状态代码,如200,302,401,500 ....... System.out.println(api.getResponse().getStatusCode()); //获取返回的包体 System.out.println(api.getResponse().getBody().toString()); //获取返回的header内容 System.out.println(api.getResponse().getHeaders()); //可以根据返回值内容进行验证 }
具体的验证内容需要在得到返回值之后进行验证,由于每个接口的返回值都不一样,所以都需要定制这些检查点.
API测试代码结构
- API类: 放置在apis目录里面
- JSON: 放置在resource的servicedescription目录下
- 测试数据文件: 放置在resource的testcase下面目录下,可以起一个子目录,名字和API相匹配
- 测试类: 放置在test目录相面
网友评论