目录[-]

单元测试B站学习网址

https://www.bilibili.com/video/BV1s5411A7aK?p=3&spm_id_from=pageDriver 

 

目录

pythonproject(文件夹)

 test_case_common(一级子文件夹)

   calculator.py(二级py文件)

   test_001_api.py(二级py文件)

 main.py(一级py文件)

calculator.py

# 函数功能类
def add(a, b):
    return a + b
def subtract(a, b):
    return a - b

test_001_api.py

# coding=utf-8
import unittest
from calculator import add, subtract

//测试类必须继承unittest.TestCase
class Test_calculator(unittest.TestCase):
    def setUp(self) -> None:
        return

    def tearDown(self) -> None:
        return

    def test_add(self):
        self.assertEqual(add(10, 5), 15)

    def test_substract(self):
        self.assertEqual(subtract(10,5),5)

main.py

# coding=utf-8
import unittest
from htmltestreport import HTMLTestReport
import time
now = time.strftime('%Y-%m-%d_%H_%M_%S_',time.localtime())
# 1.创建测试用例集
testcase = unittest.TestCase()
# 2.创建测试套件
suite = unittest.TestSuite()
# 3.创建测试加载器
loader = unittest.TestLoader()
# 4.测试套件加载测试用例集
suite.addTest(loader.discover(start_dir=r'C:\Users\Administrator\PycharmProjects\pythonProject\test_case_common',pattern='test_*.py'))
# 5.使用HTMLTestReport模块创建执行器,默认使用unittest.Testrunner()
runner = HTMLTestReport(file_path=now+'report.html',title='测试用例',description='详情')
# 6.运行执行器,suite已包含了指定文件的全部测试用例,接下来就依次执行
runner.run(suite)

简单的示例

# coding=utf-8
import unittest

class TestMyFunction(unittest.TestCase):
    def test_something(self):
        # 测试代码
        self.assertEqual(1 + 1, 2)

    def test_another_thing(self):
        # 另一个测试
        self.assertTrue(isinstance("hello", str))

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

.Unittest和pytest

 

PyTest是UnitTest的衍生品,可以结合selenium、requests来实现UI和接口自动化。

鄙视链PyTest——》UnitTest——》RobotFrameWork

UnitTest环境:在python中已经内嵌了,直接使用import unittest,就可以使用

.两个框架的差别?

1.用例编写规则:

unittest:

  1. testcases:测试用例,unittest 中执行测试的最小单元
  2. testsuites:测试套件,理解为一系列的测试用例组合在一起
  3. testfixtures:测试固件或夹具,用于测试环境的创建或销毁
  4. testloads:测试加载器,加载”测试用例“到”测试套件
  5. testrunner:测试运行器

遵守规则:

  1. 测试文件必须先导入库,import unittest
  2. 测试类必须继承unittest.TestCase
  3. 测试方法必须以test开头

—————————————————————

pytest:它是python的第三方测试框架,基于unittest的扩展框架,遵守规则:

  1. 测试文件名必须以test_开头或_test结尾
  2. 测试类命令必须以Test开头
  3. 测试方法必须test开头

2.用例的前置和后置

unittest

  • setUp和tearDown 在每个用例之前或之后运行一次,打开浏览器,加载网页/关闭网页
  • setUpclass和tearDownClass 在每个类运行之前或之后运行一次
  • setUpModule和tearDownModule 在每个模块之前和之后执行一次

pytest(功能更多)

方法级(通俗理解,在类里面的函数就是方法):

setup_mothod/teardown_mothod 在方法之前和之后(优先级靠前)

setup/teardown

函数级:

setup_function/teardown_function 在函数之前和之后

类级:

setup_class/teardown_class

模块:

setup_module/teardown_module

 

还有:还可以在函数之前加装饰器@pytest.fixture()

3.断言

unittest:assertTrue,assertEqual,assertIn(三个最常用)

pytest:assert

4.报告

unittest:htmltestrunner

pytest:插件pytest-HTML、allure

5.失败重跑

unittest:没有

pytest:pytest-rerunfailures插件

6.数据驱动

unittest:ddt

pytest:@pytest.mask.parametrize装饰器

7.用例分类执行

unittest:默认执行所有,也可以通过testsuite执行部分用例,或者-k参数

pytest:@pytest.mask

四、unittest框架做了什么

 

1.测试发现:从多个py文件中收集、加载测试用例

2.测试执行:将测试用例按照一定的顺序和条件执行,并且生成结果

3.测试判断:通过断言去判断结果是否正确

4.测试报告:统计测试进度、通过率、生成报告

五、Unittest重要组件

 

1.TestCase——测试用例

2.TestSuite——测试套件

3.TestFixture——测试固件/夹具

4.TestLoader——测试加载器

5.TestRunner——测试运行

六、TestCase(测试用例)用法

 

PS:只有单元测试可以使用,在self右侧,点击run,则只会运行这一个方法,这就是单元测试

最简单的函数

import unittest

class EcshopLogin(unittest.TestCase):
    # 测试用例
    def test01_baili(self):
        print('测试')
    def test02_baili(self):
        print('测试222')
    def test03_baili(self):
        print('测试333')

七、测试结果

.:一个句号,代表通过

F:失败

E:错误

S:跳过

八、用例执行顺序

根据测试用例的名字决定,是根据ASCII码决定顺序,所以要取一个很明确的数字ID

0-9 A-Z a-z】A=65,a=97

九、框架底层原理

def __init__(self, 
module='__main__',    #用例路径__main__表示当前模块的路径
defaultTest=None,     #待测用例的名称,默认是空
argv=None,            #接收外部参数
testRunner=None,      #"测试运行器",TextTestRunner
testLoader=loader.defaultTestLoader,  #指定使用默认的"测试用例加载器"
exit=True,            #是否在测试完成之后结束python程序
verbosity=1,          #类似命令行,代表详细的返回,如果写2,就代表简约风格;如果写0,连点都没有
failfast=None,        
catchbreak=None,
buffer=None, 
warnings=None, 
*, 
tb_locals=False):

调用代码的方式:

第一种:执行全部代码

unittest.main()

第二种:执行指定的部分用例

suite=unittest.TestSuite() suite.addTest(EcshopLogin('test01_baili')) suite.addTest(EcshopLogin('test02_baili')) unittest.TextTestRunner().run(suite)

第三种:把用例写到一个目录里

suite=unittest.TestSuite()
testcases=[EcshopLogin('test01_baili'),EcshopLogin('test02_baili')]
suite.addTests(testcases)
unittest.main(defaultTest='suite')

第四种:这个也不算麻烦,不能用os.getcwd(),这个命令拿到的是工作目录,并不一定和py所在目录一致

所以更建议使用os.path.dirname调用

suite=unittest.TestSuite()
testcases=unittest.defaultTestLoader.discover(start_dir=os.path.dirname(os.path.abspath(__file__)),pattern='*.py')
suite.addTests(testcases)
unittest.main(defaultTest='suite')

.封装unittest类

新建一个其他文件my_unit.py,将需要封装的内容调整到这里

import unittest

class MyUnit(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print('setUpClass:在每个类之前执行一次,如创建数据库、生成日志对象等')
    def setUp(self):
        print('\nsetUp:在测试用例之前的准备工作,如打开浏览器、加载网页')
    def tearDown(self):
        print('teatDown:在测试用例之后的扫尾工作,如关闭浏览器')
    @classmethod
    def tearDownClass(cls):
        print('tearDownClass:在每个类之后执行一次,如关闭数据库、销毁日志对象等')

另一个文件,作为主文件,继承它就可以使用了。

from my_unit import MyUnit

class Test(MyUnit):
    def test01_baili(self):
        print('测试baili')
    def test02_weiwei(self):
        print('测试weiwei')

.忽略测试用例

age=25
class Test(MyUnit):
    @unittest.skip('忽略')
    def test01_baili(self):
        print('测试baili')

    @unittest.skipIf(age>=25,'大于等于25岁,为真时忽略.')
    def test02_weiwei(self):
        print('测试weiwei')

    @unittest.skipUnless(age<25,'小于25岁,为假时忽略.')
    def test03_zhizhi(self):
        print('测试zhizhi')

skipUnless,为假时忽略,为真时不忽略,会打印出来。

忽略所有用例,则在类上面加装饰器

.unittest断言:

assertEqual(a,b) 断言a==b

assertNotEqual(a,b) 断言a!=b

assertTrue(a) 断言a为真

assertFalse(a) 断言a为假

assertIn(a,b) 断言a在b里

assertNotIn(a,b) 断言a不在b里

.生成HTTP报告

1.下载HTTPTestRunner,并放到python\Lib目录下,之后可直接使用

.跳过测试

class TestSkip(unittest.TestCase):
    @unittest.skip("跳过这个测试")
    def test_skip(self):
        self.fail("不应该执行")

    @unittest.skipIf(condition, "条件为真时跳过")
    def test_skip_if(self):
        pass

    @unittest.skipUnless(condition, "条件为假时跳过")
    def test_skip_unless(self):
        pass

    @unittest.expectedFailure
    def test_expected_failure(self):
        self.assertEqual(1, 0)  # 这个测试预期会失败

.命令行用法

注意,执行命令行时,需要在单元测试类,也就是包含unittest.TestCase的文件下输入,否则识别不到不会执行

# 运行所有测试
python -m unittest discover

# 运行特定测试模块(文件名)
python -m unittest test_module

# 运行特定测试类(类名)
python -m unittest test_module.TestClass

# 运行特定测试方法(类里面对应的方法)
python -m unittest test_module.TestClass.test_method

# 详细输出
python -m unittest -v

# 发现并运行所有测试(推荐方式)————文件夹对应的是,包含所有测试类的文件
python -m unittest discover -s 文件夹 -p "test_*.py"

.高级特性

# 子测试
class TestSubTest(unittest.TestCase):
    def test_even(self):
        """测试0-5是否为偶数"""
        for i in range(0, 6):
            # 如果不用with语句,执行一次后程序停止
            with self.subTest(i=i):
                self.assertEqual(i % 2, 0)
# 自定义断言
class TestCustomAssert(unittest.TestCase):
    def assertIsEven(self, value):
        self.assertEqual(value % 2, 0, f"{value} 不是偶数")

    def test_custom_assert(self):
        self.assertIsEven(4)