selenium unittest实战(2)-agileone项

2018-10-04  本文已影响0人  行水坐云

关键词:selenium unittest python3 agileone
第一篇文章,给大家介绍了unittest编码规范,这篇我们主要分析下代码逻辑结构。
先回顾下python的目录结构:

image.png

一、登录模块 test_login.py
1)模块文件导入常用的库,比如Select,ActionChains等等

image.png

2)测试类继承unittest(unittest.TestCase),一个测试类的实例就是测试用例。需要写类说明,表明测试的模块。


image.png

3)初始化和清除
测试模块主要验证4个case。
I) 验证错误的用户名登录
II) 验证错误的密码登录
III) 验证不输入用户名登录
IV) 验证正常登录
初始化有两个方法:setUpClass和setUp。setUpClass是所有的测试用例执行前会初始化。setUp是每个测试用例前会初始化。
由于不想每个测试用例都打开浏览器,可以把初始化webdriver对象放到setUpClass。


image.png

清除也有两个方法:tearDownClass和tearDown。tearDownClass是所有的测试用例执行结束后清除。tearDown是每个用例执行结束后清除。所以当所有的测试用例测试完成后,关闭浏览器。


image.png

第一条用例:验证错误的用户名登录。测试完成后,如果要执行第二条用例,必须清除输入的用户名和密码,刷新浏览器即可清除。

image.png
image.png
同时为了看到演示的效果,加一些延迟。
image.png
4)测试用例
setUpClass中写到"cls.driver=driver",相当于声明了一个类的属性,类属性是所有实例共享的,固可以直接self.driver调用webdriver对象。
后面的元素定位跟selenium一致,唯一特殊的是断言。根据断言的结果,unittest自动判断测试用例的结果。
常用的断言如下,其他的需要自行百度喽:
image.png
5)测试代码
使用 name == 'main',填写对应的测试代码。
unittest.main(verbosity=2)方法自动查找测试用例,加载执行。verbosity=2代表日志是详细级别。
driver=self.driver

代码如下:

import time
import unittest
from selenium import  webdriver
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.action_chains import ActionChains

class Test_Login(unittest.TestCase):
    '''登录模块'''
    @classmethod
    def setUpClass(cls):
        driver=webdriver.Chrome(r"d:\webdriver\chromedriver.exe")
        driver.implicitly_wait(10)
        driver.get("http://localhost/agileone/index.php")
        cls.driver=driver

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def setUp(self):
        time.sleep(3) # 为了看到演示效果
    def tearDown(self):
        time.sleep(3)  # 为了看到演示效果
        self.driver.refresh()

    def test_00_login(self):
        '''验证错误的用户名登录'''
        driver=self.driver
        driver.find_element_by_id("username").send_keys("admin1")
        driver.find_element_by_id("password").send_keys("admin")
        driver.find_element_by_id("login").click()
        time.sleep(1)
        msg=driver.find_element_by_id("msg").text
        self.assertIn("找不到该用户名",msg)

    def test_01_login(self):
        '''验证错误的密码登录'''
        driver=self.driver
        driver.find_element_by_id("username").send_keys("admin")
        driver.find_element_by_id("password").send_keys("admin1")
        driver.find_element_by_id("login").click()
        time.sleep(1)
        msg = driver.find_element_by_id("msg").text
        self.assertIn("密码输入错误", msg)

    def test_02_login(self):
        '''验证不输入用户名登录'''
        driver = self.driver
        driver.find_element_by_id("login").click()
        time.sleep(1)
        msg = driver.find_element_by_id("msg").text
        self.assertIn("用户名不能为空", msg)

    def test_03_login(self):
        '''验证正常登录'''
        driver=self.driver
        driver.find_element_by_id("username").send_keys("admin")
        driver.find_element_by_id("password").send_keys("admin")
        driver.find_element_by_id("login").click()
        time.sleep(1)
        logout=driver.find_element_by_css_selector("a[href*='logout']").text
        self.assertEqual('注销',logout)

if __name__ == '__main__':
    unittest.main(verbosity=2)

二、公告模块 test_notice.py
1)导入模块
与登录模块类似。

image.png
2)初始化和清除
setUpClass是所有用例测试之前进行初始化,所以完成登录的初始化即可。
tearDownClass所有用例测试完成之后,关闭浏览器。
image.png

公告管理模块主要验证4个用例:
I) 验证新增公告
II) 验证删除最新公告
III) 验证更新最新公告的标题
IV) 验证根据标题搜索公告。
为了保证用例与用例之间的独立性,测试之前和测试之后,都恢复到初始状态。
每个用例测试之前,都在登录后的首页状态,如下图。
每个用例准备开始测试,点击公告管理,进入模块,如下图。


测试之前.png
进入公告管理模块.png

初始化和清除设计如下:


image.png
3)验证新增公告
注意公告内容的输入需要先切换到frame里面,点击“新增”在主html。
image.png
4)验证删除最新公告
删除公告在新增之后执行,这个业务逻辑也保证了有公告可删。
万一没有公告可删时,直接断定此用例为失败状态。(self.fail('无公告,无法测试'))
image.png
5)验证更新最新公告的标题
先查找是否有最新的公告,如果没有直接断定为失败状态。如果有,点击最新公告的编辑,把原有的标题删掉,再输入"更新公告标题",最后再点击编辑。
image.png

6)验证根据标题搜索公告
搜索原有的公告不可控,所以设计为新增一个标题为test的公告。再根据这个test标题搜索。如果找到第一个搜索结果,即为成功。


image.png
7)测试代码
image.png
代码如下:
import time
import unittest
from selenium import  webdriver
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.action_chains import ActionChains

class Test_Notice(unittest.TestCase):
    '''公告模块'''
    @classmethod
    def setUpClass(cls):
        #登录
        driver=webdriver.Chrome(r"d:\webdriver\chromedriver.exe")
        driver.implicitly_wait(10)
        driver.get("http://localhost/agileone/index.php")
        driver.find_element_by_id("username").send_keys("admin")
        driver.find_element_by_id("password").send_keys("admin")
        driver.find_element_by_id("login").click()
        cls.driver=driver

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def setUp(self):
        time.sleep(3)#为了看到演示效果
        self.driver.find_element_by_css_selector("a[href*='notice']").click()#进入公告管理
    def tearDown(self):
        time.sleep(3)#为了看到演示效果
        self.driver.find_element_by_css_selector(".header a[href='/agileone/index.php']").click()#回到登录首页


    def test_00_addNotice(self):
        '''验证新增公告'''
        driver=self.driver
        driver.find_element_by_id("headline").send_keys("测试标题")
        driver.switch_to.frame(driver.find_element_by_css_selector(".ke-iframe"))
        driver.find_element_by_tag_name("body").send_keys("测试内容")
        driver.switch_to.default_content()
        driver.find_element_by_id("add").click()
        time.sleep(1)
        self.assertIn("新增数据成功",driver.find_element_by_id("msg").text)

    def test_01_delNotice(self):
        '''验证删除最新公告'''
        driver=self.driver
        new_id=driver.find_elements_by_css_selector("#dataPanel tr[id*='dtrow']")
        if new_id:
            driver.find_element_by_css_selector("#dataPanel tr:nth-of-type(1) label:nth-of-type(2)").click()
            driver.switch_to.alert.accept()
            time.sleep(1)
            self.assertIn("删除数据成功",driver.find_element_by_id("msg").text)

        else:
            self.fail("无公告,无法测试")

    def test_02_updateNotice(self):
        '''验证更新最新公告的标题'''
        driver = self.driver
        new_id = driver.find_elements_by_css_selector("#dataPanel tr[id*='dtrow']")
        if new_id:
            driver.find_element_by_css_selector("#dataPanel tr:nth-of-type(1) td:nth-last-of-type(1) label:nth-of-type(1)").click()
            time.sleep(1)
            headline=driver.find_element_by_id("headline")
            headline.clear()
            headline.send_keys("更新公告标题")
            driver.find_element_by_id("edit").click()
            time.sleep(1)
            msg=driver.find_element_by_id("msg").text
            self.assertIn("更新数据成功",msg)
        else:
            self.fail("无公告,无法更新")

    def test_03_searchNotice(self):
        '''验证根据标题搜索公告'''
        driver = self.driver
        #添加一个公告,再搜索
        driver.find_element_by_id("headline").send_keys("test")
        driver.switch_to.frame(driver.find_element_by_css_selector(".ke-iframe"))
        driver.find_element_by_tag_name("body").send_keys("test")
        driver.switch_to.default_content()
        driver.find_element_by_id("add").click()
        #输入标题搜索
        driver.find_element_by_id("reset").click()
        driver.find_element_by_id("headline").send_keys("test")
        time.sleep(1)
        driver.find_element_by_id("search").click()
        time.sleep(1)
        td=driver.find_element_by_css_selector("#dataPanel tr td:nth-of-type(2)").text
        self.assertIn('test',td)


if __name__ == '__main__':
    unittest.main(verbosity=2)

三、主程序 runner.py
为了生成HTML报告,需要导入HTMLTestRunner模块。
使用os.getcwd()获得项目的根目录,方便后续报告存入report目录。
使用defaultTestLoader实例的discover方法,自动发现测试用例。
使用time.strftime 把测试报告打上时间戳。
最后使用HTMLTestRunner实例运行所有用例。

import  unittest
import  time
import os
from HTMLTestRunner import  HTMLTestRunner

#获取项目的根目录
test_dir = os.path.join(os.getcwd())

# 自动搜索项目根目录下的所有case,构造测试集;返回TestSuite对象
discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')

# 实例化TextTestRunner类
# runner = unittest.TextTestRunner(verbosity=2)

now = time.strftime('%Y-%m-%d %H_%M_%S')  # 获取当前日期
filename = test_dir+ '\\report\\'+now + '_result.html'  # 构造出完整的文件名路径
fp = open(filename, 'wb')  # wb方式写入
runner = HTMLTestRunner(stream=fp, title='测试报告', description='agileone项目用例执行情况',verbosity=2)  #构造runner

# 使用run()方法运行测试套件(即运行测试套件中的所有用例)
runner.run(discover)

四、测试报告

image.png

小结
1.所有的自动化都注意初始化和清除,保证用例与用例之间的独立性,不要让用例之间有过多的耦合。
2.UI自动化,很多地方需要加延迟,否则代码执行过快导致无法找到元素。

上一篇下一篇

猜你喜欢

热点阅读