【python】unittest框架

【python】unit test框架

  • unittest组成
    • TestCase
    • TestSuite & TestRunner
      • 查看用例结果
    • TestLoader
    • 测试夹具
      • 方法级别
      • 类级别
      • 模块级别
      • 案例
      • 练习
  • 断言
    • 案例
  • 参数化
    • 参数化代码
    • 利用json
  • 跳过
  • 测试报告
    • 自带的测试报告
    • 生成第三方的测试报告

unittest组成

  • TestCase (最核心的模块)
    测试用例,每个TestCase 都是一个代码文件,在这个代码文件中来书写真正的用例代码。
  • TestSuite
    测试套件,用来管理、组装(打包)多个TestCase
  • TestRunner
    测试执行,用来执行TestSuite
  • TestLoader
    测试加载,对TestSuite的补充
  • Fixture
    测试夹具,书写在TestCase 代码中,是一个代码结构,可以在每个方法执行前后都会执行的内容

TestCase

创建demo.py

# 1.导包
import unittest


# 2.自定义测试类,需要继承unittest模块中的TestCase类
class TestDemo(unittest.TestCase):
    # 3.书写测试方法
    # 书写要求:测试方法必须以test_开头
    def test_method1(self):
        print('测试方法1')

    def test_method2(self):
        print('测试方法2')
# 4.执行用例(方法)
# 4.1将光标放在类名的后边运行
# 4.2将光标放在方法名的后边运行,只执行当前的方法

TestSuite & TestRunner

创建demo1.py,demo2.py
创建suite_runner.py

# 1.导包
import unittest

from demo1 import TestDemo1
from demo2 import TestDemo2

# 2.实例化(创建对象)套件对象
suite = unittest.TestSuite()
# 3.使用套件对象添加用例方法
# 方式1:套件对象.addTest(测试类名('方法名'))
suite.addTest(TestDemo1('test_method1'))
suite.addTest(TestDemo1('test_method2'))
suite.addTest(TestDemo2('test_method1'))
suite.addTest(TestDemo2('test_method2'))
# 方式2:将一个测试类中的所有方法进行添加 套件对象.addTest(unittest.makeSuite(测试类名))
suite.addTest(unittest.makeSuite(TestDemo1))
suite.addTest(unittest.makeSuite(TestDemo2))
# 4.实例化运行对象
runner = unittest.TextTestRunner()
# 5.使用运行对象去执行套件对象
runner.run(suite)

查看用例结果

【python】unittest框架_第1张图片
运行结果中 . 用例通过,F 用例不通过, E error 用例代码有问题

TestLoader

创建tools.py

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

创建test,test1,test2

import unittest

from tools import add


class TestAdd(unittest.TestCase):
    def test_method1(self):
        if add(1, 2) == 3:
            print('测试通过1')
        else:
            print('测试不通过2')

    def test_method2(self):
        if add(10, 20) == 30:
            print('测试通过1')
        else:
            print('测试不通过2')

    def test_method3(self):
        if add(2, 2) == 5:
            print('测试通过1')
        else:
            print('测试不通过2')

创建testloader.py

# 1.导包
import unittest
# 2.实例化加载对象并添加用例
# unittest.TestLoader().discover('用例所在的路径','用例的代码文件名')
suite = unittest.TestLoader().discover('./case', '*.py')
# 3.实例化运行对象
# runner = unittest.TextTestRunner()
# 4.执行
# runner.run(suite)

# 可以将3.4.5变为一步
unittest.TextTestRunner().run(suite)

使用默认对象的写法:

# 1.导包
import unittest
# 2.使用默认的加载对象并加载用例
suite=unittest.defaultTestLoader.discover('case','*.py')
# 可以将3.4.5变为一步
unittest.TextTestRunner().run(suite)

测试夹具

方法级别和类级别,前后的方法,不需要同时出现,根据用例代码的需要自行选择使用

方法级别

在每个测试方法(用例代码)执行前后都会自动调用的结果

# 方法执行之前
def setUp(self):
	每个测试方法执行前都会执行
	pass

# 方法执行之后
def tearDown(self):
	每个测试方法执行之后都会执行
	pass

类级别

在每个测试类中所有方法执行前后都会自动调用的结构(在整个类中执行之前执行之后各一次)

# 类级别的Fixture方法,是一个类方法
# 类中所有方法之前
@classmethod
def setUpClass(cls):
	pass
	
@classmethod
def tearDownClass(cls):
	pass

模块级别

在每个代码文件执行前后执行的代码结构

# 模块级别的需要写在类的外边直接定义函数即可
# 代码文件之前
def setUpModule():
	pass
	
# 代码文件之后
def tearDownModule():
	pass

案例

1.打开浏览器(整个测试过程中只打开一次浏览器) 类级别
2.输入网址 (每个测试方法都要一次) 方法级别
3.输入用户名密码验证码点击登录(不同的测试数据)测试方法
4.关闭当前页面(每个测试方法都要一次) 方法级别
5.关闭浏览器 (整个测试过程中只关闭一次浏览器)类级别

创建fixture.py

import unittest


class TestLogin(unittest.TestCase):
    def setUp(self):
        '''每个测试方法执行前都会先调用的方法'''
        print('输入网址...')

    def tearDown(self) -> None:
        '''每个测试方法执行后都会调用的方法'''
        print('关闭当前页面...')

    @classmethod
    def setUpClass(cls) -> None:
        print('...1.打开浏览器')

    @classmethod
    def tearDownClass(cls) -> None:
        print('...5。关闭浏览器')
    def test_1(self):
        print('输入用户名密码验证码,点击登录 1')

    def test_2(self):
        print('输入用户名密码验证码,点击登录 2')

练习

创建tools.py:

def login(username, password):
    if username == 'admin' and password == '123456':
        return '登录成功'
    else:
        return '登录失败'

创建login_test.py:

import unittest

from tools import login


class TestLogin(unittest.TestCase):
    def test_username_password_ok(self):
        if login('admin', '123456') == '登录成功':
            print('pass')
        else:
            print('fail')

    def test_username_error(self):
        if login('root', '123456') == '登录失败':
            print('pass')
        else:
            print('fail')

    def test_password_error(self):
        if login('admin', '123123') == '登录失败':
            print('pass')
        else:
            print('fail')

    def test_username_password_error(self):
        if login('root', '123123') == '登录失败':
            print('pass')
        else:
            print('fail')

断言

断言结果有两种:true 用例通过 ; false 代码抛出异常,用例不通过
在unittest中使用断言,都要通过self. 断言方法
assertEqual:判断预期结果和实际结果是否相等
self.assertEqual(预期结果,实际结果)

assertIn:判断预期结果是否包含在实际结果中
self.assertIn(预期结果,实际结果)

案例

创建assert.py

import unittest

from tools import login


class TestLogin(unittest.TestCase):
    def test_username_password_ok(self):
        self.assertEqual('登录成功',login('admin', '123456'))
        '''
        if login('admin', '123456') == '登录成功':
            print('pass')
        else:
            print('fail')
        '''

    def test_username_error(self):
        self.assertEqual('登录失败', login('root', '123456'))

    def test_password_error(self):
        self.assertEqual('登录失败', login('admin', '123123'))
        
    def test_username_password_error(self):
        #self.assertEqual('登录失败', login('root', '123123'))
        self.assertIn('失败', login('root', '123123'))
       

【python】unittest框架_第2张图片
【python】unittest框架_第3张图片

参数化

在测试方法中,使用变量来代替具体的测试数据,然后使用传参的方法将测试数据传递给方法的变量
好处:相似的代码不需要多次书写
安装插件:pip install parameterized ,使用pip list查看已安装插件

参数化代码

1.导包:unittest/ pa
2.定义测试类
3.书写测试方法(测试数据使用变量代替)
4.组织测试数据并传参

创建pa.py

# 1.导包:unittest/ pa
import unittest
from parameterized import parameterized
from tools import login
# 2.定义测试类


# 组织测试数据 [(),(),()] or [[],[],[]]
data = [
    ('admin', '123456', '登录成功'),  # 与测试方法中参数顺序保持一致
    ('root', '123456', '登录失败'),
    ('admin', '123123', '登录失败')
]


class TestLogin(unittest.TestCase):
    # 3.书写测试方法(测试数据使用变量代替)
    @parameterized.expand(data)  # 4.组织测试数据并传参(装饰器@)
    def test_login(self, username, password, expect):
        self.assertEqual(expect, login(username, password))

利用json

创建data.json

[
  {
    "desc": "正确的用户名和密码",
    "username": "admin",
    "password": "123456",
    "expect": "登录成功"
  },
  {
    "desc": "错误的用户名和密码",
    "username": "root",
    "password": "123123",
    "expect": "登录失败"
  },
  {
    "desc": "错误的用户名",
    "username": "root",
    "password": "123456",
    "expect": "登录失败"
  }
]

修改pa.py

# 1.导包:unittest/ pa
import json
import unittest
from parameterized import parameterized
from tools import login


# 2.定义测试类
# 组织测试数据 [(),(),()] or [[],[],[]] 列表套元组 或 列表套列表
def build_data():
    with open('data.json', encoding='utf-8') as f:
        result = json.load(f)  # [{},{},{}]
        data = []
        for i in result:  # i 是每一个字典
            data.append((i.get('username'), i.get('password'), i.get('expect')))
    return data


class TestLogin(unittest.TestCase):
    # 3.书写测试方法(测试数据使用变量代替)
    @parameterized.expand(build_data())
    def test_login(self, username, password, expect):
        self.assertEqual(expect, login(username, password))
# 4.组织测试数据并传参(装饰器@)

跳过

对于一些未完成的或者不满足测试条件的测试函数和测试类,不想执行,可以跳过
书写在TestCase文件中:
@unittest.skip('跳过的原因') 直接将测试函数标记成跳过
@unittest.skipIf(判断条件,'跳过原因') 根据条件判断测试函数是否跳过

import unittest

version = 30


class TestDemo(unittest.TestCase):
    @unittest.skip('没有原因,跳过')
    def test_1(self):
        print('测试方法1')

    @unittest.skipIf(version >= 30, '版本大于等于30,不用测试')
    def test_2(self):
        print('测试方法2')

    def test_3(self):
        print('测试方法3')

测试报告

自带的测试报告

只有单独运行TestCase的代码,才会生成测试报告
【python】unittest框架_第4张图片

生成第三方的测试报告

HTMLTestRunner
1.获取第三方的测试运行类模块,放入代码目录
2.导包unittest
3.使用套件对象,加载对象 添加用例方法
4.实例化第三方的运行对象,并运行套件对象

创建test.py

# 1.获取第三方的测试运行类模块,放入代码目录
# 2.导包unittest
import unittest
from HTMLTestRunner import HTMLTestRunner

# 3.使用套件对象,加载对象 添加用例方法
suite = unittest.defaultTestLoader.discover('.', 'paj.py')
# 4.实例化第三方的运行对象,并运行套件对象
#HTMLTestRunner()
# stream=sys.stdout, 测试报告的文件对象(open),要使用wb打开
# verbosity=1, 可选,报告的详细程度,默认 1 简略,2 详细
# title=None, 可选,测试报告标题
# description=None 描述信息,python版本等等
file = 'report.html'  # 报告的后缀是.html
with open(file, 'wb') as f:
    runner = HTMLTestRunner(f,2,'测试报告','python 3.7')  # 运行对象

    # 运行对象执行套件
    runner.run(suite)

【python】unittest框架_第5张图片

  1. 组织用例文件(TestCase里面),书写参数化,断言,Fixture,跳过;如果只有单个测试文件,直接运行,得到测试报告,如果有多个测试文件,需要组装运行生成测试报告
  2. 使用套件对象组装,或加载对象组装
  3. 运行对象 运行
    运行对象=第三方的运行类(文件对象(打开文件需要使用wb方式))
    运行对象.run(套件对象)

创建report_ch.py

import unittest
from HTMLTestRunnerCN import HTMLTestReportCN

suite = unittest.defaultTestLoader.discover('.', 'paj.py')
# HTMLTestReportCN()
# stream=sys.stdout, verbosity=1,title=None,description=None,tester=None
with open('report_cn.html', 'wb') as f:
    runner = HTMLTestReportCN(f)
    runner.run(suite)

你可能感兴趣的:(软件测试,python,单元测试)