美文网首页
selenium unittest实战(2)-agileone项

selenium unittest实战(2)-agileone项

作者: 行水坐云 | 来源:发表于2018-10-04 11:20 被阅读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自动化,很多地方需要加延迟,否则代码执行过快导致无法找到元素。

    相关文章

      网友评论

          本文标题:selenium unittest实战(2)-agileone项

          本文链接:https://www.haomeiwen.com/subject/cbkxaftx.html