Selenium Java+PageObject+Maven+TestNg 开源分享

测试小书童 · 2017年05月10日 · 最后由 战 神 回复于 2017年12月27日 · 2618 次阅读

说明

selenium3+java 自动化测试

功能

  • maven 管理
  • testng 配置测试类
  • yaml 维护用例
  • PageObject 模式

用法

初始化 mavnen

.....
            <<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.20</version>
                <configuration>
                    <suiteXmlFiles>
                        <suiteXmlFile>res/testng.xml</suiteXmlFile>
                    </suiteXmlFiles>
                </configuration>
                <executions>
                <execution>  <!--集成测试-->
                    <id>failsafe-integration-tests</id>
                    <phase>integration-test</phase>
                    <goals>
                        <goal>integration-test</goal>
                    </goals>
                </execution>
            </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.11</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-chrome-driver</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.esotericsoftware.yamlbeans</groupId>
            <artifactId>yamlbeans</artifactId>
            <version>1.11</version>
        </dependency>
    </dependencies>
</project>

配置 PageObject

以登录为例子,所有的 page 都由三部分构成:

  • 构造函数
  • 操作方法
  • 检查点
public class LoginPage {
    YamlRead yamlRead;
    OperateElement operateElement;
    protected WebDriver driver;
    private boolean isOperate = true;
    /***
     * 默认构造函数
     * @param driver
     * @param path yaml配置参数
     */
    public LoginPage(WebDriver driver, String path) {
        this.driver = driver;
        yamlRead = new YamlRead(path);
        operateElement= new OperateElement(this.driver);
    }

    /***
     * 测试步骤
     * @throws YamlException
     * @throws FileNotFoundException
     */
    public void operate() throws YamlException, FileNotFoundException, InterruptedException {
        List list = (List) yamlRead.getYmal().get("testcase");
//        System.out.println(list);
        for(Object item: list){
            TestCase testCase = new TestCase();
            testCase.setFind_type((String) ((Map)item).get("find_type"));
            testCase.setElement_info((String) ((Map)item).get("element_info"));
            testCase.setText((String) ((Map)item).get("text"));
            testCase.setOperate_type((String) ((Map)item).get("operate_type"));
            if (!operateElement.operate(testCase)) {
                isOperate = false;
                System.out.println("操作失败");
                break;
            }

        }
    }

    /***
     * 检查点
     * @return
     * @throws YamlException
     * @throws FileNotFoundException
     */
    public boolean checkpoint() throws YamlException, FileNotFoundException, InterruptedException {
        if (!isOperate) { // 如果操作步骤失败,检查点也就判断失败
            System.out.println("操作步骤失败了");
            return false;
        }
        List list = (List) yamlRead.getYmal().get("check");
        for(Object item: list){
                CheckPoint checkPoint = new CheckPoint();
                checkPoint.setElement_info((String) ((Map)item).get("element_info"));
                checkPoint.setFind_type((String) ((Map)item).get("find_type"));
                if (!operateElement.checkElement(checkPoint)) {
                    return false;
                }
            }

        return true;
    }

配置登录的 yaml

testcase:
    - element_info: user_login
      find_type: id
      operate_type: send_keys
      text: lose
    - element_info: user[password]
      find_type: name
      operate_type: send_keys
      text: password
    - element_info: //*[@id="new_user"]/div[4]/input
      find_type: xpath
      operate_type: click
check:
    - element_info: /html/body/div[1]/nav/div/ul[1]/li/a/img
      find_type: xpath
    - element_info: /html/body/div[1]/nav/div/ul[2]/li[2]/a
      find_type: xpath

登录测试

public class LoginPageTest extends TestBaseSetup {
    private WebDriver driver;

    @BeforeClass
    public void setUp() {
        driver=getDriver();
    }
    @Test
    public void testLogin() throws YamlException, FileNotFoundException {
        LoginPage loginPage = new LoginPage(this.driver, "/Login.yaml");
        loginPage.operate();
        Assert.assertTrue(loginPage.checkpoint(), "检查点不通过");
    }
}

个人中心测试

public class MyinfoPageTest extends TestBaseSetup {
    private WebDriver driver;

    @BeforeClass
    public void setUp() {
        driver=getDriver();
    }
    @Test
    public void testMyInfo() throws YamlException, FileNotFoundException {
      // 前置条件是登录成功
        LoginPage loginPage = new LoginPage(this.driver, "/Login.yaml");
        loginPage.operate();

        MyInfoPage myInfoPage = new MyInfoPage(this.driver, "/Myinfo.yaml");
        myInfoPage.operate();
        Assert.assertTrue(myInfoPage.checkpoint(), "检查点不通过");
    }
}

配置 testng

<suite name="TesterHome" parallel="tests" thread-count="2"> <!-- 并行地执行test套件-->
    <parameter name="appURL" value="https://testerhome.com/account/sign_in"/>
    <parameter name="browserType" value="chrome"/>
    <parameter name="driverPath" value="C:\Program Files (x86)\Google\Chrome\Application\"/>
    <listeners>
        <listener class-name="util.ExtentTestNGIReporterListener"/> <!-- 测试报告-->
        <listener class-name="util.TestMonitor"/> <!-- 打印日志-->
    </listeners>
    <test name="登录">
        <classes>
            <class name="test.LoginPageTest"/>
        </classes>
    </test>
    <test name="社区">
        <classes>
            <class name="test.MyinfoPageTest"/>
        </classes>
    </test>
</suite>

配置 testng

<suite name="TesterHome">
    <parameter name="appURL" value="https://testerhome.com/account/sign_in"/>
    <parameter name="browserType" value="chrome"/>
    <parameter name="driverPath" value="C:\Program Files (x86)\Google\Chrome\Application\"/>
    <test name="登录">
        <classes>
            <class name="test.LoginPageTest"/>
        </classes>
    </test>
    <test name="个人页面">
        <classes>
            <class name="test.MyinfoPageTest"/>
        </classes>
    </test>
</suite>

测试结果

开源地址

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 18 条回复 时间 点赞

大神,请给一个此文章的完整项目工厂,3q

更新:

  • docker 的引入,支持多设备并行
尹全旺 回复

page 相当于逻辑处理层,代码分层的基本概念

cooling 回复

可以了,已经开源了,文章最前面贴了地址

我意思是,比如登录,按照你的思路,很多元素得重复写,应该把元素分出来,可以在 yaml 用例中 include page,这样就得到了页面元素,也不会有重复问题

看了一下,发现有几个问题,在此提出来,帖子中 通过 yaml 去维护用例 ,是很好的一种方式,但是当你每需要一份 yml 用例时,就意味着需要多一个类文件去维护,当页面特别多的的时候 ,就会非常积累,应该在此之上再多加一层考虑,类文件减少维护,只去维护 yml 的用例文件

不错 跟我现在设计的用例体系很像 你的例子还太少

恩,补了一个个人中心用例

开始从 python 转战 Java 了👍 👍

测试小书童 TestNg+extentreports 生成测试报告 中提及了此贴 05月12日 11:47

你不觉得用 yaml 来写 case 啥的 也是挺蛋疼的一件事情么?

0x43 回复

为什么要转 java?

alam.zheng 回复
  • 依赖包的管理。打包好用
  • 方便执行单元测试和集成测试,持续集成

能不能以页面为 yaml,该页面上以功能或者模块为区分写用例呢?还有公有的页面元素不能抽出来吗?我觉得还是一个页面的用例卸载一个 yaml 比较好吧

phinexdaz 回复

我也觉得写代码更直观,其实简单培训下业务人员是可以写脚本的

@lose ,问下我的疑问,既然用例都用 yaml 写出来了,也有解析的方法,为什么一定要用 page 这个概念呢,不能直接写 testcase 吗?

有个疑问,就比如登录来说,登录那么多场景,那么你每次的元素信息不都得重复写一次,这样是不是太冗余,而且一个 yaml 就只能写一条用例吗?

还是直接用代码写 case 比较爽

请问 maven 的作用是?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册