第三章 编写测试用例
好了,在前面的两章,咱们大概知道pytest是怎么工作的了,现在让咱们开始学习怎么写测试用例吧。主要内容包括如何用类、模块、目录来组织测试,以便管理大量的测试用例,还有使用marker来标记希望同时运行的用例,或者跳过某些用例,或者标记预期失败的用例。
3.1 使用assert断言
如果你用过unittest,那么一定会被那一堆assert开头的断言函数烦死,然而,pytest使用的是Python自带的assert关键字(实际上经过了重新封装,能提供更多信息),只需要在assert后面添加表达式,就可以很轻松地实现断言的功能。下面看下对比:
pytest | unittest |
assert something | assertTrue(something) |
assert a == b | assertEqual(a, b) |
assert a <= b | assertLessEqual(a, b) |
... | ... |
参考咱们前面章节用过的代码:
# F:\Pytest_learning\ch01\test_one.py
import pytest
@pytest.mark.demo01
def test_passing():
print('测试是否会打印出来')
assert (1, 2, 3) == (1, 2, 3)
# F:\Pytest_learning\ch01\test_two.py
def test_failinig():
local = '局部变量'
assert (1, 2, 3) == (3, 2, 1)
# F:\Pytest_learning\ch01\ch01_sub\test_three.py
import pytest
def add(x, y):
return x + y
def test_add_1():
assert add(1, 2) == 3
@pytest.mark.demo01
def test_add_2():
assert add(2, 2) == add(1, 4)
断言失败会抛出AssertError异常:
3.2 跳过测试
不知道同学们还记不记得上一章咱们在介绍-m选项的时候曾经提过的对用例进行标记的操作,其实pytest也有自己内置(就是固定含义)的标记,例如skip和skipif,没错了,就是字面意义上的跳过的意思,用于跳过一些不想要执行的用例(例如需要修改暂时用不上,或者在某些条件下不可用)。内置标记与自定义标记的区别在于内置标记都带()。举个例子,新建ch02目录(这里换了电脑,所以变成了D盘),新增test_skip.py文件内容如下:
import pytest
version = 5
def add(x, y):
return x + y
def test_add_1():
assert add(1, 2) == 3
@pytest.mark.skip(reason = "这里是跳过的原因")
def test_add_2():
assert add(2, 2) == 3
@pytest.mark.skipif(version == 5, reason = "如果版本号等于5就跳过")
def test_add_3():
assert add(2, 2) == 3
让我们执行一下ch02目录的用例,结果如下:
可以看到,执行结果是.ss,s表示skip跳过,@pytest.mark.skip(reason="这里是跳过的原因")用于直接跳过该条用例不执行(仍可以被检测到),而@pytest.mark.skipif(version = 5, reason = "如果版本号=5就跳过")则是依据括号内设置第一个参数的表达式是否成立来判断要不要执行,version这里等于5,成立,所以这条用例就被跳过了,同学们可以自己试下改成不成立是不是就不会跳过哦。
3.3 预期失败
顾名思义,就是用来标记一些预计原本就不会执行通过的用例,用法和跳过有点类似,新建test_xfail.py文件,内容如下:
import pytest
version = 5
def add(x, y):
return x + y
@pytest.mark.xfail()
def test_add_1():
assert add(2, 2) == 3 # 预期失败,实际失败
@pytest.mark.xfail()
def test_add_2():
assert add(2, 2) == 4 # 预期失败,实际成功
来吧,执行一下:
可以看到,这次结果是x和X,小x代表xfailed即预期失败,实际也失败了;大X表示xpassed即预期失败实际却成功了。
3.4 预期异常
假如咱们做的就是异常测试(例如检查代码是否能正确抛出指定的异常报错,实际中可能用的比较少),那么代码中如果报了异常,用例不就执行失败了么?为了应付这种情况,可以使用 with pytest.raises(异常名)来证明代码抛出了咱们想要的异常,注意,这次不是用的标记了。举个例子,新建ch03目录,新增test_exceptions.py文件内容如下:
import pytest
def test_add_raises():
'''测试一个肯定会报ValueError异常的用例'''
str_to_change = '非数字字符不能转数字'
num = int(str_to_change)
直接执行,结果如下:
修改代码如下:
import pytest
def test_add_raises():
'''测试一个肯定会报ValueError异常的用例'''
str_to_change = '非数字字符不能转数字'
with pytest.raises(ValueError): # 预期下面的代码会抛ValueError
num = int(str_to_change)
执行结果如下:
如果抛出的是其他的异常,或者没有异常,那么测试用例仍是失败的哦。
3.5 组织测试用例合集
之前咱们说过怎么用-m标记运行指定的用例,但是实际工作中,一般都会事先把用例放到同个文件夹或者文件里,不会这么麻烦。接下来介绍下批量运行用例的方法:
3.5.1 单个目录
一般直接cd到目标目录,然后执行执行pytest命令即可,例如3.2的操作。
3.5.2 单个文件
cd到文件所在目录后,执行pytest+文件名,例如3.3和3.4的操作。
3.5.3 单个测试类
这里提到的测试类,和python里的类的概念其实是一样的,就是将某些测试函数组合到一起,有面向对象的意思,举个例子,新建文件test_class.py:
class TestClass():
"""这是一个测试类的例子"""
def test_class_01(self):
assert 1 == 1
def test_class_02(self):
assert 2 == 2
def test_03():
assert 3 == 3
如果我直接执行文件,那么有3个用例:
如果我在文件名后面加上::和测试类的名字,则
如果我只想执行某个用例或者测试类中的某个用例,可以继续加::和用例名称
3.5.4 指定包含某个名字的用例
请用看上一章的-k参数(https://blog.csdn.net/weijiaxin2010/article/details/90342027)
下一章《第四章 参数化测试》