Web自动化之Unittest框架

情到浓时终转凉″ 提交于 2019-12-20 23:12:56


今日目标

  • 能够使用UnitTest定义测试用例并运行
  • 记住TestSuite作用及使用方式
  • 记住TextTestRunner作用及使用方式
  • 了解TestLoader作用及使用方式
  • 掌握定义方法级别的Fixture
  • 掌握定义类级别的Fixture
  • 了解定义模块级别的Fixture
  • 了解断言的概念
  • 能够使用assertEqual、assertIn进行断言

UnitTest 框架

  • 什么是框架?
    • 框架英语单词是framework
    • 为解决一类事情的功能集合
  • 什么是UnitTest框架?
    • 概念:UnitTest是Python自带的一个单元测试框架,用它来做单元测试。
  • 为什么使用UnitTest框架?
    • 能够组织多个用例去执行
    • 提供丰富的断言方法
    • 能够生成测试报告
  • UnitTest核心要素
    • TestCase
    • TestSuite
    • TestRunner
    • TestLoader
    • Fixture

1. TestCase(测试用例)

  • 代码步骤
1.导包:import unittest
2.定义测试类:新建测试类必须继承unittest.TestCase
3.定义测试方法:测试方法名称命名必须以test开头
  • 执行方法
1.类后 unittest 运行,类后 unittest 运行 
2.运行所有的方法运行所有的方法
3.命令行运行,测试用例增加 main 方法
	调用 unittest.main() 来运行
  • 代码演示1
import unittest

def add(x,y):
    num = x + y
    return num

# 类继承 unittest.TestCase
class TestADD01(unittest.TestCase):
    def test_add0101(self):
        number = add(2, 3)
        print('number1的值:', number)
        
    def test_add0102(self):
        number = add(2,2)
        print('number2的值是:', number) 
        
if __name__ == '__main__':
    unittest.main()
  • 代码演示2
import unittest

def add(x,y):
    num = x + y
    return num

# 类继承 unittest.TestCase
class TestADD02(unittest.TestCase):

    def test_add0201(self):
        number = add(1,1)
        print('number1的值是:', number)

    def test_add0202(self):
        number = add(2,2)
        print('number2的值是:', number)

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

2. TestSuite(测试套件)

说明:(翻译:测试套件)多条测试用例集合在一起,就是一个TestSuite
使用:
    1. 实例化: suite = unittset.TestSuite()
    			(suite:为TestSuite实例化的名称)
    2. 添加用例:
    		方法一:suite.addTest(ClassName("MethodName"))
    		(ClassName:为类名;MethodName:为方法名)
    		
   			方法二:suite.addTest(unittest.makeSuite(ClassName))
   			(搜索指定ClassName类名内test开头的方法并添加到测试套件中)

提示:TestSuite需要配合TestRunner才能被执行

  • 代码演示
import unittest
from hm01_test_add import TestADD01
from hm02_test_add import TestADD02

# 组装测试用例
# 1.实例化一个suite对象
suite = unittest.TestSuite()

# 2.增加测试用例
# 方式一: suite.addTest(ClassName("MethodName"))
suite.addTest(TestADD01("test_add0101"))
suite.addTest(TestADD01("test_add0102"))

# 3.增加测试用例 方式二: suite.addTest(unittest.makeSuite(ClassName))
suite.addTest(unittest.makeSuite(TestADD02))

# 4.实例化一个runner
runner = unittest.TextTestRunner()

# 5.调用run(suite)
runner.run(suite)

3.TextTestRunner(测试用例执行)

说明:TextTestRunner是用来执行测试用例和测试套件的
使用:
	1. 实例化:runner = unittest.TextTestRunner()
	2. 执行: runner.run(suite) # suite:为测试套件名称

4. TestLoader(组装测试用例)

说明:
    1.用来加载TestCase到TestSuite中,即加载满足条件的测试用例,并把测试用例封装成测试套件。
    2.使用unittest.TestLoader,通过该类下面的discover()方法自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件。

用法:
	suite = unittest.TestLoader().discover('文件夹路径', pattern="*.py")
	
解释:	
	自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件
	pattern:为查找的.py文件的格式,默认为'test*.py'
	也可以使用unittest.defaultTestLoader 代替 unittest.TestLoader()
	
运行:
	runner = unittest.TextTestRunner()
	runner.run(suite)
  • 代码演示
# 运行10个py文件
# 导包
import unittest
# 调用discover() 方法  找文件  文件路径  寻找规则
loader = unittest.TestLoader().discover("./cases", pattern="*.py")
# 运行组装好的测试用例
runner = unittest.TextTestRunner()
runner.run(loader)
  • TestLoader与TestSuite区别
1. TestSuite需要手动添加测试用例,可以添加测试类(makeSuite(类名)),也可以添加测试类中某个测试方法(类名+方法名),更加灵活;
2. TestLoader搜索指定目录下指定开头.py文件,并添加测试类中的所有的测试方法,不能指定添加测试方法,多个文件要运行时,更加简单方便;

5. Fixture

说明:Fixture是一个概述,对一个测试用例环境的初始化和销毁就是一个Fixture

定义: 测试用例包含 数据准备, 用例功能, 数据恢复 结构内容

Fixture控制级别:
    1. 方法级别
    2. 类级别
    3. 模块级别
  • 代码演示1
# 完成两个方法,实现打印每个方法的消耗时间
import unittest
import time

class TestTime(unittest.TestCase):
    def tBegin(self):
        print("开始的时间:", int(time.time()))

    def tEnd(self):
        print("结束的时间:", int(time.time()))

    def test_t01(self):
        self.tBegin()
        print('*' * 20)
        time.sleep(2)
        self.tEnd()

    def test_t02(self):
        self.tBegin()
        print('=' * 20)
        time.sleep(2)
        self.tEnd()
  • 代码实现步骤:

    • 方法级别:

      1. 初始化(前置处理):
      	def setUp(self) --> 每个方法执行前, 自动执行
      2. 销毁(后置处理):
      	def tearDown(self) --> 每个方法结束后, 自动执行
      3. 运行于测试方法的始末,即:运行一次测试方法就会运行一次setUp和tearDown
      
    • 代码演示2

    import unittest
    class TestFixture(unittest.TestCase):
        def setUp(self):
            print('setUp每个方法执行前,执行 --001')
        def tearDown(self):
            print('tearDown每个方法执行后,执行 --001')
        def test_f01(self):
            print('我是方法1)
        def test_f02(self):
            print('我是方法2')    
    
    • 类级别:

      1. 初始化(前置处理):
      	@classmethod
      	def setUpClass(cls): --> 类开始前自动执行
      2. 销毁(后置处理):
      	@classmethod
      	def tearDownClass(cls): --> 类结束后自动执行
      3. 运行于测试类的始末,即:每个测试类只会运行一次setUpClass和tearDownClass
      
    • 代码演示3

    import unittest
    class TestFixture(unittest.TestCase):
        @classmethod
        def setUpClass(cls):
            print('类开始前,执行———————————————————————002')
            
        @classmethod
        def tearDownClass(cls):
            print('类结束后,执行———————————————————————002')
        
        def setUp(self):
            print('setUp每个方法执行前,执行 --001')
            
        def tearDown(self):
            print('tearDown每个方法执行后,执行 --001')
        
       	def test_f01(self):
            print('我是方法1')
    
        def test_f02(self):
            print('我是方法2')             
    
    • 模块级别:

      1. 初始化(前置处理):
      	def setUpModule() --> 模块执行前自动执行
      2. 销毁(后置处理):
      	def tearDownModule() --> 模块执行后自动执行
      3. 运行于整个模块的始末,即:整个模块只会运行一次setUpModule和tearDownModule
      
    • 代码演示4

    import unittest
    
    def setUpModule():
     	print('模块开始前:****************************003')
         
    def tearDownModule():
        print('模块结束后:****************************003')
    
    class TestFixture(unittest.TestCase):
        @classmethod
        def setUpClass(cls):
            print('类开始前,执行———————————————————————002')
        
        @classmethod
        def tearDownClass(cls):
            print('类结束后,执行———————————————————————002')
           
        def setUp(self):
            print('setUp每个方法执行前,执行 --001')
            
        def tearDown(self):
            print('tearDown每个方法执行后,执行 --001')
            
        def test_f01(self):
            print('我是方法1')
            
        def test_f02(self):
            print('我是方法2')
    
    • 代码演示5
    # 需求:使用UnitTest框架对tpshop项目测试
    # 1). 点击登录,进入登录页面
    # 2). 输入用户名和密码,不输入验证码,直接点击登录按钮
    # 3). 获取错误提示信息
    import unittest
    from selenium import webdriver
    from time import sleep
    
    class TestLogin(unittest.TestCase):
        def setUp(self):
            self.driver = webdriver.Firefox()
            self.driver.get('http://127.0.0.1/')
        	self.driver.implicitly_wait(10)
            self.driver.maximize_window()
        
        def tearDown(self):
            sleep(2)
            self.driver.quit()    
            
        def testlogin(self):
            # 1).点击登录,进入登录页面
            self.driver.find_element_by_link_text('登录').click()
            # 2). 输入用户名和密码,不输入验证码,直接点击登录按钮
           	sleep(2) 
        	self.driver.find_element_by_id('username').send_keys('admin')
           	sleep(2) 
            self.driver.find_element_by_id('password').send_keys('xxxxxx')
            sleep(2) 
            self.driver.find_element_by_class_name('J-login-submit').click()
            
            # 3).获取错误提示信息
            sleep(2)
            msg = self.driver.find_element_by_class_name('layui-layer-content')
            text = msg.text
            print("提示信息:", text)
    

6. 断言

  1. 断言概念:

    让程序代替人为判断测试程序执行结果是否符合预期结果的过程
    
  2. 为什么学习断言?

    自动化脚本在执行的时候一般都是无人值守状态,我们不知道执行结果是否符合预期结果,所以我们需要让程序代替人为检测程序执行的结果是否符合预期结果,这就需要使用断言。
    
  3. 断言的方法:

    1.assertEqual(预期结果, 实际结果)
    2.assertTrue(预期结果==实际结果)
    3.assertIn(预期结果, 实际结果) --> 实际结果包含预期结果
    
  4. 异常类:AssertionError

  5. 代码演示1

    import unittest
    
    def add(x, y):
        num = x + y
        return num
    
    class TestAdd(unittest.TestCase):
        def test_add01(self):
            result1 = add(2, 3)
            print(result1)
            self.assertEqual(5, result1)
            
        def test_add02(self):
            result2 = add(3, 5)
            print(result2)
            is_equal = result2==8
            self.assertTrue(is_equal)
    
  6. 代码演示2

    # 需求:使用UnitTest框架对tpshop项目测试
    # 1). 点击登录,进入登录页面
    # 2). 输入用户名和密码,不输入验证码,直接点击登录按钮
    # 3). 获取错误提示信息
    # 4). 断言错误提示信息是否为“验证码不能为空!”,如果断言失败则保存截图
    import unittest
    from selenium import webdriver
    from time import sleep
    import time
    import sys
    
    class TestLogin(unittest.TestCase):
        def setUp(self):
            self.driver = webdriver.Firefox()
            self.driver.get('http://127.0.0.1/')
        	self.driver.implicitly_wait(10)
            self.driver.maximize_window()
        
        def tearDown(self):
            sleep(2)
            self.driver.quit()    
            
        def testlogin(self):
            # 1).点击登录,进入登录页面
            self.driver.find_element_by_link_text('登录').click()
            # 2). 输入用户名和密码,不输入验证码,直接点击登录按钮
           	sleep(2) 
        	self.driver.find_element_by_id('username').send_keys('admin')
           	sleep(2) 
            self.driver.find_element_by_id('password').send_keys('xxxxxx')
            sleep(2) 
            self.driver.find_element_by_class_name('J-login-submit').click()
            
            # 3).获取错误提示信息
            sleep(2)
            msg = self.driver.find_element_by_class_name('layui-layer-content')
            text = msg.text
            print("提示信息:", text)
            
            # 断言
            # assertEqual('验证码不能为空!', text)
            
            try:
            	self.assertEqual('这是怎么了', text)
                
            except Exception as e:
                ee = sys.exc_info()
                print('异常的详细信息:',ee)
                print('异常的详细信息:',ee[1])
            
                # self.driver.get_screenshot_as_file('./123.png')
                
                # 获取当前时间戳 年月日 时分秒
                now_f = time.strftime('%Y%m%d_%H%M%S')
                self.driver.get_screenshot_as_file('./screenshot%s.png' % now_f)
                print('错误信息', e)
                
                # 抛出异常
                raise e
    

定位不到元素怎么处理?

  1. 元素属性定位,检查属性是否正确
  2. 换其他方式 8种方式。
  3. 等待时间,确保元素加载出来
  4. 元素在别的Frame上, 切换frame
  5. 元素在别的窗口, 切换窗口
  6. HTML结构比较复杂, 定位到上某一个层级, 定位到这个元素。
  7. 页面元素发生变化, 刷新页面。
  8. 百度查询
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!