32、Selenium + Python 实现 UI 自动化测试-正片4

再来写几条用例吧。

创建一个新文件test_new_bug.py文件,用来新建bug

from selenium import webdriver
import unittest

class TestNewBug(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(20)
        self.driver.maximize_window()
        self.driver.get("http://localhost:81/redmine/login")
        self.driver.find_element_by_id('username').clear()
        self.driver.find_element_by_id('username').send_keys('admin')
        self.driver.find_element_by_id('password').clear()
        self.driver.find_element_by_id('password').send_keys('test1234')
        self.driver.find_element_by_id('login-submit').click()

    def test_new_bug(self):
        self.driver.find_element_by_xpath('//*[@id="top-menu"]/ul/li[3]/a').click()
        self.driver.find_element_by_xpath('//*[@id="projects-index"]/ul/li[1]/div/a').click()
        self.driver.find_element_by_xpath('//*[@id="main-menu"]/ul/li[4]/a').click()
        #点击新建问题按钮
        self.driver.find_element_by_xpath('//*[@id="content"]/div[1]/a').click()
        #输入bug简要描述
        self.driver.find_element_by_id('issue_subject').send_keys('【RedMine系统测试】【新建Bug模块】:问题简要描述')
        js1 = "window.scrollTo(0,document.body.scrollHeight)"
        self.driver.execute_script(js1)
        #点击创建
        self.driver.find_element_by_name('commit').click()
        ele = self.driver.find_element_by_id('flash_notice')
        self.assertIn('已创建',ele.text)

    def tearDown(self):
        self.driver.quit()

if __name__ == '__main__':
    TestNewBug()

运行结果:pass (单条用例调试通过)


尝试运行下run.py,看下是否能将之前的2条case,加上今天新写的case,一起运行完成,然后看下测试报告,是否包含3条用例执行结果。

执行成功(大家注意下自动化运行的过程:先执行的login,然后执行的new_bug,最后执行的new_pj),HTML报告结果如下图:

32、Selenium + Python 实现 UI 自动化测试-正片4

现在我们的框架目录文件:

32、Selenium + Python 实现 UI 自动化测试-正片4

用例排序是按照字母的升序进行的。执行顺序是按照用例顺序依次执行的。

虽然本次运行没有错误,这是因为我们之前已经有项目了,而我们新建bug,只是随便选了个项目,在其下面新建的bug。如果第一次运行,没有项目,势必会报错。

意思就是,我们创建的用例,某些情况下,会有前后逻辑关系,需要依次执行。如何解决该问题?

那我们就修改下用例名命名规则吧,如下:

32、Selenium + Python 实现 UI 自动化测试-正片4

运行,成功,按照我们期望的顺序执行。


在写第三条用例的时候,再setup里面又写了一遍登录过程,

32、Selenium + Python 实现 UI 自动化测试-正片4

每次都写这么多代码,让我很不爽,就算复制粘贴也“难消心头之恨”。是否可以将这部分“公共”的东西拿出来呢?

好,我们再次调整下框架目录结构,新建一个common目录,用来存放这些“公共”部分,如下

32、Selenium + Python 实现 UI 自动化测试-正片4

新建一个login.py文件,写一个登录函数,直接导入该文件,就可以调用该函数,内容如下:

from selenium import webdriver

def Login():
    driver = webdriver.Chrome()
    driver.implicitly_wait(20)
    driver.maximize_window()
    driver.get("http://localhost:81/redmine/login")
    driver.find_element_by_id('username').clear()
    driver.find_element_by_id('username').send_keys('admin')
    driver.find_element_by_id('password').clear()
    driver.find_element_by_id('password').send_keys('test1234')
    driver.find_element_by_id('login-submit').click()
    return driver

if __name__ == '__main__':
    Login()

然后调整一下 test_001_new_pj 和 test_002_new_bug 文件,内容如下:

import unittest
from selenium import webdriver
import time
from time import sleep
from first.common import login

class TestNewProject(unittest.TestCase):
    def setUp(self):
        self.driver = login.Login()

    def test_new_pj(self):
        project_name = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))
        project_id = "bs" + project_name  # 标识要求以字母开头
        self.driver.find_element_by_xpath('//*[@id="top-menu"]/ul/li[3]/a').click()  # 点击左上角“项目”
        self.driver.find_element_by_xpath('//*[@id="content"]/div[1]/a').click()  # 点击新建项目
        self.driver.find_element_by_id('project_name').send_keys(project_name)  # 输入项目名称
        self.driver.find_element_by_id('project_identifier').send_keys(project_id)  # 输入项目标识
        js1 = "window.scrollTo(0,document.body.scrollHeight)"
        self.driver.execute_script(js1)  # 创建按钮不在当前屏幕内,需要先滑动滚动条
        self.driver.find_element_by_name('commit').click()  # 点击创建按钮
        sleep(2)
        ele1 = self.driver.find_element_by_id('flash_notice')
        self.assertEqual(ele1.text,'创建成功')

    def tearDown(self):
        self.driver.quit()

if __name__ == '__main__':
    TestNewProject()

可以看到setup 里面的一大坨内容,变成了一句话,清爽了许多。


简单总结一下:

1、我们在写新的case时,发现case在目录中的存储顺序是按照字母先后排列的,执行顺序也是如此;但有的时候这并不是我们想要的,于是我们稍微调整了一下case名称。

2、在写新case的时候,我们setup里面代码是从前面粘过来的,为了简化代码,我们将登录部分写成了一个函数,需要的时候调用函数就行。