python+selenium+unittest自动化脚本用例设计

       这里的示例以网易邮箱为例,可以自己注册一个来练习,要说明的是,直接在网易的首页进行定位是定不了的,网易进行过处理;这里是通过百度搜索在搜索结果中进行的定位。

unittest认识

unittest是python内置的单元测试框架,具备编写用例、组织用例、执行用例、输出报告等自动化框架的条件。
使用unittest前需要了解该框架的五个概念: 即test case,test suite,testLoader,test runner,test fixture。

  • test case  :一个完整的测试单元,执行该测试单元可以完成对某一个问题的验证,完整体现在:
  •            测试前环境准备(setUp),执行测试代码(run),以及测试后环境还原(tearDown);
  • test suite  :多个测试用例的集合,测试套件或测试计划;
  • testLoader  :加载TestCase到TestSuite中的,其中loadTestsFrom__()方法用于寻找TestCase,并创建它们的实例,然后添加到TestSuite中,返回TestSuite实例;
  • test runner :执行测试用例,并将测试结果保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息;
  • test fixture:一个测试用例的初始化准备及环境还原,主要是setUp() 和 setDown()方法;

unitest的工作原理

通过unittest类调用分析,可将框架的工作流程概况如下:
编写TestCase,由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite, 最后将运行的结果保存在TextTestResult中。

#coding:utf8
from selenium import webdriver  # webdriver属于selenium的API
import unittest  # unittest是python自带的模块
import time
class test_mail_login(unittest.TestCase):  # 定义一个类并集成 unittest 基类中的 TestCase 类
    def setUp(self):   # 每个测试case运行之前运行(前置条件)
        self.driver = webdriver.Chrome()  # 驱动谷歌浏览器
        self.driver.get("https://www.baidu.com")  # 获取百度URL
        self.driver.set_window_size(800, 1000)  # 窗口大小设置
        # self.driver.maximize_window()  # 窗口最大化
        time.sleep(2)
        self.driver.find_element_by_id("kw").send_keys("网易")  # 百度输入框定位并键入关键字
        time.sleep(3)
        self.driver.find_element_by_id("su").click()  # 点击搜索按钮
        self.driver.implicitly_wait(5)  # 页面静置5秒,无任何动作
    def test_mail_loginsuc(self):  # 设计测试用例(case)重点注意,方法名必须以【test_】开头
        self.driver.find_element_by_id("op_email3_username").send_keys("testerhunter")
        time.sleep(2)
        self.driver.find_element_by_class_name("op_email3_password").send_keys("123456hunter")
        time.sleep(2)
        self.driver.find_element_by_class_name("c-btn").click()
        self.handles = self.driver.window_handles  # 获取所有句柄
        self.driver.switch_to_window(self.handles[-1])  # 句柄转换,获得当前句柄
        time.sleep(3)
        txt = self.driver.find_element_by_id("spnUid").text  # 获取页面固定内容的文本
        print(txt)
        self.assertEqual(txt, "[email protected]")  # 做断言处理,判断实际结果与期望结果是否一致
    def tearDown(self):  # 每个测试case运行完之后执行(后置条件)
        self.driver.delete_all_cookies()  # 清空所有cookies值,让页面更清洁,反应更快,避免造成缓存问题
        self.driver.quit()  # 关闭浏览器

if __name__ == '__main__':
    unittest.main()  # 这种执行方式,用例的执行顺序是无序的

python Unittest中setUp与setUpClass的区别

  1. setUp():每个测试case运行之前运行
  2. tearDown():每个测试case运行完之后执行
  3. setUpClass():必须使用@classmethod 装饰器,  所有case运行之前只运行一次
  4. tearDownClass():必须使用@classmethod装饰器, 所有case运行完之后只运行一次

控制用例执行顺序

#coding:utf8
from selenium import webdriver  # webdriver属于selenium的API
import unittest  # unittest是python自带的模块
import time
class test_mail_login(unittest.TestCase):  # 定义一个类并集成 unittest 基类中的 TestCase 类
    @classmethod
    def setUpClass(cls):   # 每个测试case运行之前运行(前置条件)
        cls.driver = webdriver.Chrome()  # 驱动谷歌浏览器
        cls.driver.get("https://www.baidu.com")  # 获取百度URL
        cls.driver.set_window_size(800, 1000)  # 窗口大小设置
        # self.driver.maximize_window()  # 窗口最大化
        time.sleep(2)
        cls.driver.find_element_by_id("kw").send_keys("网易")  # 百度输入框定位并键入关键字
        time.sleep(3)
        cls.driver.find_element_by_id("su").click()  # 点击搜索按钮
        cls.driver.implicitly_wait(5)  # 页面静置5秒,无任何动作
    def test_mail_loginsuc(self):  # 设计测试用例(case)重点注意,方法名必须以【test_】开头
        self.driver.find_element_by_id("op_email3_username").send_keys("testerhunter")
        time.sleep(2)
        self.driver.find_element_by_class_name("op_email3_password").send_keys("123456hunter")
        time.sleep(2)
        self.driver.find_element_by_class_name("c-btn").click()
        self.handles = self.driver.window_handles  # 获取所有句柄
        self.driver.switch_to_window(self.handles[-1])  # 句柄转换,获得当前句柄
        time.sleep(3)
        txt = self.driver.find_element_by_id("spnUid").text  # 获取页面固定内容的文本
        print(txt)
        self.assertEqual(txt, "[email protected]")  # 做断言处理,判断实际结果与期望结果是否一致
    @classmethod
    def tearDownClass(cls):  # 每个测试case运行完之后执行(后置条件)
        cls.driver.delete_all_cookies()  # 清空所有cookies值,让页面更清洁,反应更快,避免造成缓存问题
        cls.driver.quit()  # 关闭浏览器

if __name__ == '__main__':
    # 使用TestSuite可以控制用例的顺序,用例的执行顺序是由添加到TestSuite的顺序决定的
    tests = [test_mail_login('test_mail_loginsuc')]  # 以列表的形式添加用例
    suite = unittest.TestSuite()  # 实例化一个用例对象suite
    # suite.addTest(test_mail_login('test_mail_loginsuc'))  # 执行单个用例
    suite.addTests(tests)  # 将测试用例实例增加到测试套件中
    runner = unittest.TextTestRunner()  # 实例化一个运行的对象runner
    runner.run(suite)  # 执行用例对象

这里参考一篇博客(https://blog.51cto.com/2681882/2123613)做一个批量类型用例的展示,会涉及到导模块的问题:

待测模块【myfunc.py】:

#encoding=utf8
def is_prime(num):
    if num < 0 or num in (0,1):
        return False
    for element in range(2,num):
        if num % element == 0:
            return False
    return True

def add(a,b):
    return a + b

def divide(a,b):
    return a/b

编写unittest测试用例【test_myfunc.py】:

#encoding=utf8
import unittest
from myfunc import is_prime,add,divide

class TestMyFunc(unittest.TestCase):
    def setUp(self):
        print('每个用例执行前会调用setUp方法准备环境')

    @classmethod
    def setUpClass(cls):
        print('所有用例执行前,只执行一次。')

    def test_is_prime(self):
        print('is_prime')
        self.assertTrue(is_prime(5))
        self.assertFalse(is_prime(8))
        self.assertFalse(is_prime(0))
        self.assertFalse(is_prime(1))
        self.assertFalse(is_prime(-3))

    def test_add(self):
        print('add')
        self.assertEqual(3, add(1,2))
        self.assertEqual(3, add(2, 2))

    def test_divide(self):
        print('divide')
        self.assertEqual(2,divide(6,3))
        self.assertNotEqual(2,divide(5,2))

    def tearDown(self):
        print('每个用例执行后会调用tearDown方法进行环境清理')

    @classmethod
    def tearDownClass(cls):
        print('所有用已执行完,只执行一次!')

if __name__ == '__main__':
    tests = [TestMyFunc('test_is_prime'),TestMyFunc('test_add'),TestMyFunc('test_divide')]
    suite = unittest.TestSuite().addTests(tests)
    unittest.TextTestRunner().run(suite)
    # unittest.main()

运行结果如下:

D:\xuexi\Python34\python.exe "D:\xuexi\PyCharm 2016.3.1\helpers\pycharm\utrunner.py" E:\Pythonworkspace\autotest\day01\test_myfunc.py true
Testing started at 9:23 ...
所有用例执行前,只执行一次。
每个用例执行前会调用setUp方法准备环境
add
每个用例执行后会调用tearDown方法进行环境清理

Failure
Traceback (most recent call last):
  File "E:\Pythonworkspace\autotest\day01\test_myfunc.py", line 24, in test_add
    self.assertEqual(3, add(2, 2))
AssertionError: 3 != 4

每个用例执行前会调用setUp方法准备环境
divide
每个用例执行后会调用tearDown方法进行环境清理
每个用例执行前会调用setUp方法准备环境
is_prime
每个用例执行后会调用tearDown方法进行环境清理
所有用已执行完,只执行一次!

Process finished with exit code 0
在unittest中,用例是以test开头的方法定义的,默认执行顺序是根据用例名称升序进行,如上面的用例, 实际执行顺序为:test_add-->test_divide-->test_is_prime,而不是用例定义的先后顺序。
使用unittest对myfunc进行单元测试,首先需要导入unitest框架和待测模块myfunc,定义的测试用例方法类 需要继承unittest.TestCase,且测试用例方法是以test开头作为标识,用例的执行结果以assetxxx断言结果 决定,如果断言返回为false,将抛出assetError异常(AssertionError: 3 != 4)。

注意:要是在导包遇到问题,比如上面的【from myfunc import is_prime,add,divide】会报红线,在编译的时候是通不过的,关于路径问题就自己解决了,一般都是放在相对路径下,这里放在相对路径下,并且要改变 package 的属性为 【sources root】:

      python+selenium+unittest自动化脚本用例设计_第1张图片

需要将【HTMLTestRunner.py】下载并安放到python安装包的【lib】目录中即可使用,以下给出下载地址:

链接:https://pan.baidu.com/s/1SpW9PZpUgkrCAWK8cYlg6Q 
提取码:6csz 

对于以上测试用例输出HTML格式的输出报告,直接在 if 模块中加入报告输出内容即可,如果这种方式不可行,那么我们可以把运行内容单独提出来写一个模块,如下【run.py】模块内容:

import time
import unittest
from HTMLTestRunner import HTMLTestRunner
if __name__ == '__main__':
    testdir = './'  # 定义相对路径为当前路径
    discover = unittest.defaultTestLoader.discover(testdir, pattern='test_*.py')  #查找当前路径下所有满足test_*.py格式的模块内的测试用例
    now = time.strftime('%Y-%m-%d %H-%M-%S', time.localtime(time.time()))  #格式化时间,为后面输出测试报告做准备
    repoertpath = open(r'E:/autotest/' + now + '.html', 'wb')  #指定测试报告的存放路径
    runner = HTMLTestRunner(stream=repoertpath,title=u'自动化测试报告',description='testcase_excute !')  #实例化测试报告模块的测试报告对象
    runner.run(discover)
    repoertpath.close()

python+selenium+unittest自动化脚本用例设计_第2张图片

现在把上面的中合起来,做一个跨包的测试用例编写即输出报告打印,用例代码就不给出来了,写出来即可,像以下模式:

       python+selenium+unittest自动化脚本用例设计_第3张图片

需要引入【sys】模块进行路径下的文件调取:

#encoding:gbk
import HTMLTestRunner#导入测试报告模块
import unittest
import sys
import time
sys.path.append("./add/")#利用python标准库中的sys模块中的path来添加本地能识别的add目录
sys.path.append("./sbu/")
sys.path.append("./tester/")
sys.path.append("./day01")
testdir = './'#定义相对路径为当前路径
discover = unittest.defaultTestLoader.discover(testdir,pattern='test_*.py')#查找当前路径下所有满足test_*.py格式的模块内的测试用例
now = time.strftime("%Y-%m-%d %H-%M-%S",time.localtime(time.time()))#格式化时间,为后面输出测试报告做准备
repath = open(r"E:/autotest/"+now+".html","wb")#指定测试报告的存放路径
print(discover)
if __name__ == '__main__':
    runner = HTMLTestRunner.HTMLTestRunner(stream=repath,title=u"自动化测试报告",description=u"对测试用例的输出报告分析")#实例化测试报告模块的测试报告对象
    runner.run(discover)#执行上面跨目录找到的说有符合'test_*.py'模块中的测试用例,并将执行结果输出到测试报告

  python+selenium+unittest自动化脚本用例设计_第4张图片

会遇到很多问题:诸如编码格式、输出报告打印不出来、能打印出报告但是内容为空等等,都需要我们去分析,调整。

你可能感兴趣的:(Python)