软件测试攻略(二十四):界面自动化之testNG&Java封装

一、testNG

TestNG是Java中的一个测试框架。Java中已经有一个JUnit的测试框架了。 TestNG比JUnit功能强大的多。 测试人员一般用TestNG来写自动化测试。 开发人员一般用JUnit写单元测试。
上一篇已经提过,我们在pom.xml里面添加了testNG的依赖


image.png

二、testNG注解:

@BeforeSuite
    被@BeforeSuite注解的方法,将会在testng定义的xml根元素里面的所有执行之前运行
@AfterSuite
    被@AfterSuite注解的方法,将会在testng定义的xml根元素里面的所有执行之后运行。
@BeforeTest
    被@BeforeTest注解的方法,将会在一个元素定义的所有里面所有测试方法执行之前运行。
 @AfterTest
    被@AfterTest注解的方法,将会在一个元素定义的所有里面所有的测试方法执行之后运行。
 @BeforeClass
    被@BeforeClass注解的方法,将会在当前测试类的第一个测试方法执行之前运行。
@AfterClass
    被@AfterClass注解的方法,将会在当前测试类的最后一个测试方法执行之后运行。
@BeforeMethod
    被@BeforeMethod注解的方法,将会在当前测试类的每一个测试方法执行之前运行。
@AfterMethod
    被@AfterMethod注解的方法,将会在当前测试类的每一个测试方法执行之后运行
@Test 注解
    @Test 注解是TestNG的核心注解,被打上该注解的方法,表示为一个测试方法

暂时我们先主要记住:

  • @BeforeClass
    被@BeforeClass注解的方法,将会在当前测试类的第一个测试方法执行之前运行。
  • @AfterClass
    被@AfterClass注解的方法,将会在当前测试类的最后一个测试方法执行之后运行。
  • @Test 注解
    @Test 注解是TestNG的核心注解,被打上该注解的方法,表示为一个测试方法

二、如何使用testNG

我们给设置环境变量、打开浏览器这个方法,添加注解@BeforeClass,表示在第一个测试方法执行之前运行。给关闭浏览器这个方法添加注解@AfterClass,表示在最后一个测试方法执行之后运行。

@BeforeClass
    public void startUp() {
        //设置环境变量,指定chromedriver的路径
        System.setProperty("webdriver.chrome.driver",
                "src/main/resources/driver_2_38_v65-67/chromedriver.exe");
        //设置浏览器的参数
       ChromeOptions options = new ChromeOptions();
        //最大化浏览器
       options.addArguments("--test-type", "--start-maximized");
        //打开浏览器
        driver = new ChromeDriver();
    }
@AfterClass
    public void shutDown(){
        //关闭浏览器
        driver.close();
        //关闭浏览器驱动
        driver.quit();
    }
@Test
    public void openUrl(){
        //打开要测的登录页面
        driver.get("http://www.guoyasoft.com:8080/guoya-client");
    }
@Test
    //登录
    public void login() {
        //定位用户名框
        WebElement userName= driver.findElement(By.id("userName"));
        userName.clear();
        //输入用户名
        userName.sendKeys("wuling");
        //定位密码框
        WebElement password= driver.findElement(By.id("password"));
        password.clear();
        //输入密码
        password.sendKeys("0000");
        //定位并点击登录
        driver.findElement(By.id("loginBtn")).click();
    }

给我们要测试的方法添加@test注解,上述代码给打开网页方法和登录方法添加@test注解
如何使用
在给方法添加testNG注解后,直接右键类run as -> testNG test**

image.png

但是执行@test的顺序是怎样的呢?
1、按照字母表顺序执行测试方法
如果需要测试的方法只有@Test,那么它将通过方法名的首字母按照字母表顺序执行
2、给方法添加priority属性
根据业务逻辑,给各个方法添加priority属性,按照@Test(priority = 0)——>@Test(priority = 1)——>……@Test(priority = N)执行。
3、在testNG.xml配置顺序(推荐)
testNG.xml的基本结构如下:
image.png

image.png

将testNG.xml拖到包下面。


image.png

testNG.xml右键,run as -> testNG Suit


image.png

观察执行结果:
image.png

三、Java封装

实际的工作中,我们避免在业务流有过多的代码干扰,我们的业务操作,基本是定位元素-操作元素,比如输入用户名、密码、校验码的基本套路都是,定位文本框-清除文本框-向输入文本内容,那我们是否可以把这个套路封装成一个方法,需要用时,只用填几个参数,而节省空间去写几行代码。

 //定位用户名框
WebElement userName= driver.findElement(By.id("userName"));
//清除
userName.clear();
//输入用户名
userName.sendKeys("wuling");

将他封装成一个方法,

public void textInput(String xp,String texts) {
        WebElement textInp= driver.findElement(By.xpath(xp));
        textInp.clear();
        textInp.sendKeys(texts);
}

当我们需要操作文本框时,只要调用这个方法,并且写入文本框的地址,和要输入的内容作为参数即可。

textInput("//input[@id=userName]","wuling");

原本的三行代码,写成一行即可。
我们新建一个class文件来专门写工具流,用一个专门写业务流,这样代码更清晰明了。而且,工具流以后可以重复使用。业务逻辑更改,直接更改业务流即可,提高效率。
我们将工具流新建为AutoBasic.class,

public class AutoBasic {
    public WebDriver driver; //将driver设置为全局变量
        //启动浏览器
    public void startUp() {
    //设置环境变量,指定chromedriver的路径
        System.setProperty("webdriver.chrome.driver",
                "src/main/resources/driver_2_38_v65-67/chromedriver.exe");
        //设置浏览器的参数
       ChromeOptions options = new ChromeOptions();
        //最大化浏览器
       options.addArguments("--test-type", "--start-maximized");
        //打开浏览器
        driver = new ChromeDriver(options);
        sleep() ;
    }
        //关闭浏览器
    public void shutDown(){
        //关闭浏览器
        sleep() ;
        driver.close();
        //关闭浏览器驱动
                driver.quit();
    }
    public void sleep() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public void openUrl(String url){
        //打开要测的登录页面
        driver.get(url);
        sleep();
        
    }
    //input文本
    public void textInput(String xp,String texts) {
        WebElement textInp= driver.findElement(By.xpath(xp));
        textInp.clear();
        textInp.sendKeys(texts);
        sleep();
    }
    //点击按钮
    public void buttonInput(String xp) {
        WebElement buttonInp= driver.findElement(By.xpath(xp));
        buttonInp.click();
    }
    //下拉框
    public void selectFunction(String xp, int i) {
        Select select =new Select(driver.findElement(By.xpath(xp)));
        select.selectByIndex(i);
    }   
    //刷新
    public void navRefresh() {
        driver.navigate().refresh();
        sleep();
    }

新建一个class文件是业务流,SearchAuto.java

public class SearchAuto {
    AutoBasic fz =new AutoBasic();//要使用AutoBasic.class的方法,先要实例化
    //打开浏览器
    @BeforeClass
    public void startUp() {
        fz.startUp();
    }
    @AfterClass
    public void shutDown() {
        fz.shutDown();
    }
    //打开网页
    @Test
    public void openUrl() {
        fz.openUrl("http://47.98.226.232:8080/guoya-medium/jsp/user/login.jsp");
    }
    @Test
  //登录
    public void login() {
    //输入用户名
        fz.textInput("//input[@id=\"userName\"]","guoya");
    //输入密码
        fz.textInput("//input[@id=\"password\"]","Aa123!");
    //输入验证码
        fz.textInput("//input[@id=\"checkCode\"]","12345");
   // 点击登录
        fz.buttonInput("//input[@id=\"loginBtn\"]");
    }
    @Test
    //查询
    public void searchUN() {
        fz.textInput("//input[@name=\"userName\"]","guoya");
    //点击查询
        fz.buttonInput("//tr[2]/td[8]/input");
    }
    @Test
    public void navRefresh() {
        fz.navRefresh();
    }
    @Test
    public void searchEdu() {
        fz.selectFunction("//tr[1]/td[6]/select", 2);
        fz.buttonInput("//tr[2]/td[8]/input");
    }

可以看到,按照业务逻辑,使用工具流里的方法,简单清晰不迷糊。

四、java封装_参数化

public void login() {
        fz.textInput("//input[@id=\"userName\"]","guoya");
        fz.textInput("//input[@id=\"password\"]","Aa123!");
        fz.textInput("//input[@id=\"checkCode\"]","12345");
        fz.buttonInput("//input[@id=\"loginBtn\"]");
}

我们可以进一步讲这套代码封装,将可能需要更改的数据写成参数

public void login(String um,String pwd) {
        fz.textInput("//input[@id=\"userName\"]",um);
        fz.textInput("//input[@id=\"password\"]",pwd);
        fz.textInput("//input[@id=\"checkCode\"]","12345");
        fz.buttonInput("//input[@id=\"loginBtn\"]");
}

这样我们完成整个登录,就只需要写:

login("guoya","Aa123!");

五、testNG参数化及断言

(一)断言
在Jmeter里我们已经了解过断言,它相当于预期结果,一条测试用例,除了测试步骤,测试数据,必须要有断言,与Jmeter相同的,如果不设置断言,如果不设置判断,那自动化没有意义。
语句:
Assert.assertEquals(result, true);
result是实际结果和true为预期结果,实际结果与预期结果做比较,一般用Boolean值做断言数据。
在工具流AutoBasic.java写入一个新的方法,得到实际的结果,返回一个boolean值。

public  boolean assertPage(String s) {
        boolean result=driver.getPageSource().contains(s);
        return result;
    }
@test
//登录成功测试用例
public void loginSuccess(String um, String pwd){
 //打开网页
        openUrl();
//登录
        login("guoya","Aa123!");
//实际结果,如果登录成功跳转到查询页面,故以“查询”来做断言,
//如果登录成功,应该返回true,如果登录不成功,应该返回false
        boolean result1=fz.assertPage("查询");
//实际结果与预期结果比较
        Assert.assertEquals(result1, true);
    }

(二)参数化
testNG有两种参数化方式

  1. Parameters
  • 在testNG.xml里面配置参数化数据
<parameter name="userName" value="guoya"></parameter> 
<parameter name="password" value="Aa123!"></parameter> 
image.png

name后面是变量名,value后面是变量值,成对,即
userName="guoya"
password="Aa123!"

  • 那如何使用呢
@Parameters({"userName","password"})
    public void loginSuccess( String um, String pwd){
        openUrl();
        login(um,pwd);
        boolean result1=fz.assertPage("查询");
        Assert.assertEquals(result1, true);
                

将原本的@test改为@Parameters({"userName","password"})即可。
代码进一步可以修改为

@Parameters({"userName","password"})
public void loginSuccess( String um, String pwd, String exp1){
 //exp1就是断言,用断言结果与true做比较,
//如果断言结果为true,exp结果为true,如果断言结果为false,exp结果为false
        boolean exp=exp1.equals("true");
    openUrl();
    login(um,pwd);
    boolean result1=fz.assertPage("查询");
    if(result1){
        Assert.assertEquals(result1, exp);
    }else{
        Assert.assertEquals(result1, exp);
    }
}
  1. dataprovider
    步骤
    (1)使用@Test(dataProvider="sdata")给测试方法添加注解使用参数化的数据;
    (2)需要自己写一个方法来存储数据
    方法1:二维数组存数据
    @DataProvider(name="dataLogin")
    public Object[][] dataLogin() {
        Object[][] ob = new Object[4][3];//一组数据组成一条测试用例
    //一条测试用例
    //测试数据
        ob[0][0]="wuling";
        ob[0][1]="0000";
  //断言
        ob[0][2]="true";
   //一条测试用例
        ob[1][0]="wuling1";
        ob[1][1]="0000";
        ob[1][2]="false";
   //一条测试用例
        ob[2][0]="wuling";
        ob[2][1]="0001";
        ob[2][2]="false";
   //一条测试用例
        ob[3][0]="wuling12";
        ob[3][1]="0022";
        ob[3][2]="false";
        return ob;
    }

方法2:csv文件存数据


image.png

保存为csv文件,

    @DataProvider(name="dataLogin")
    public static Object[ ][ ] dataLogin() {
        Object[ ][ ] obData = CSVReader.readCSV("E:/softwareData/dataLogin.csv");
        return obData;
    
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 感谢原作者的奉献,原作者博客地址:http://blog.csdn.net/zhu_ai_xin_520/arti...
    狼孩阅读 14,003评论 1 35
  • 本文首发于 https://jaychen.cc作者 jaychen 写一篇小文,介绍一下 Java 下单元测试工...
    jaychenIsUsed阅读 1,870评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 文/十二月墨 一座陌生的城市,不知该往哪走! 一颗千疮百孔的心,只是想找个陌生的环境让它安静而已! 爱情,曾经让我...
    十二月墨阅读 396评论 0 3
  • 清晨六点,像冬眠的小兽感知到春之温煦般,沉睡的意识自然觉醒,像黑夜里悄然亮起的一盏灯;紧接着,像是暂停的音乐重新播...
    M梦兮阅读 418评论 2 7