selenium unittest实战(2)-agileone项目

关键词: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自动化,很多地方需要加延迟,否则代码执行过快导致无法找到元素。

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

推荐阅读更多精彩内容

  • 洞见SELENIUM自动化测试 写在最前面:目前自动化测试并不属于新鲜的事物,或者说自动化测试的各种方法论已经层出...
    厲铆兄阅读 6,724评论 3 47
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,008评论 25 707
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,710评论 2 59
  • 夜幕细风雨霏霏,漫步芳草间。红粉烟绿柳丝垂,朵朵都随风。 片片落花纷飞远,醉眼看花艳。浮生杳杳空悲切,过眼云烟梦。
    夏诺xn阅读 572评论 40 41
  • 本周的作业是觉察自己: 1. 觉察记录体会自己—平时你是否尊重孩子? 尊重孩子时候比较多,而且有的时候会娇纵。 2...
    Juliachen_3ccd阅读 227评论 0 0