Test Cases by pytest

这篇同样是“拿来”的。 pytest will run all files in the current directory and its subdirectories of the form test_.py or _test.py. More generally, it follows standard test discovery rules.

python中的package和module

module

module用于组织一系列相关的functionclass,在文件系统中体现为一个.py文件。

package

package用于组织一些列相关的module,在文件系统中体现为一个含有若干.py文件的文件夹。 不过要让python理解某个文件夹是package,需要在该文件夹中添加一个名为__init__.py的文件。__init__.py文件可以为空(这个文件有其他功能,这里不讨论)

文件夹可以存放其他文件夹,同理,package也可以包含其他的package。

文件系统中的文件组织形式

因此,python中的packagemodule,在文件系统中看应该是这样的

1
2
3
4
5
6
7
8
9
10
11
12
package1/
__init__.py
module1.py
module2.py
package2/
__init__.py
module1.py
module2.py
package3/
__init__.py
module1.py
module2.py

如何让python找到自己编写的package

如果我们自己写了一个program.py文件,希望它能够使用自己编写的package或者module,如何让python能够找到自己编写的packagemodule呢?

例如,在program.py中使用import导入所需的函数

1
2
from package.module1 import some_function1
from module3 import some_function2

有以下几种方法

package文件夹和module文件放在和program.py同级的文件夹下

1
2
3
4
5
6
7
8
9
someFolder/
program.py
package/
__init__.py
module1.py
module2.py
...
module3.py
...

package文件夹和module文件放在python安装目录下的site-packages文件夹下

我自己ubuntu系统用anaconda发行版,site-packages的位置是/home/usr/anaconda3/lib/python3.5/site-packages

放在任意路径,将所在路径加入PYTHONPATH环境变量(这个方法对于anaconda似乎无效)

建议方法

这里建议的方式搭配Git,让Git统一管理package的版本演变,而每个项目单独clone一份所需的package。这样既能够保证有一份统一的代码,也不会由于向后兼容问题导致以前项目的代码无法运行。

pytest的基本用法

pytest测试用例代码的组织方式

由于团队使用代码时可能随时会对已有的代码做出修改,修改后要运行测试用例确保没有引入新的问题。因此将测试用例代码和功能代码放在一起会比较方便。建议的方式是

1
2
3
4
5
6
7
8
9
10
packageName/
__init__.py
module1.py
module2.py
...
test/
__init__.py
test_module1.py
test_module2.py
...

注意test文件夹下也需要添加 __init__.py成为package,否则test_module1.py等测试代码使用如下的relative import的时候就会报错

1
from ..module1 import func

如果要运行测试用例代码,可以在packageName所在的路径打开terminal,运行

1
py.test

然后pytest会自动遍历所有test_开头的module,然后执行其中test开头的function,以及Test开头的classtest开头的method并给出测试结果。

因此如果希望module, function, class, class methodpytest自动识别的话, 记得用test开头命名。(对于class, 使用Test)

测试用例的写法

例如写了下面一个功能函数func,功能是返回一个字符串s复制n次后进行拼接的结果,如果s不是字符串,那么抛出TypeErrorException,并提示s should be string!。那么测试用例可以这么写。

1
2
def test_value():
assert func('ab',3) == 'ababab'

这里的关键是利用assert语句

1
assert [condition]

的功能是判断condition是否成立, 如果成立,什么也不发生,否则的话会raise Exceptionpytest识别。

condition的内容一般是如果我们的函数正常生效,应该产生什么样的结果。

再上面的这个例子里,如果func(s, n)生效,那么func('ab', 3)应该等于'ababab'

为了检测s不为字符的时候,func是否正确的raise Exception,可以这么写。

1
2
3
4
5
def test_error():
with pytest.raises(TypeError) as error_info:
func(1,3)
assert 's should be string!' == str(error_info.value)

这里可以用pytest.raises构造一个context-container,然后构造一个场景,故意让被测函数触发raise Exception的场景。

Exception的信息会被error_info捕捉, 然后检查str(error_info.value)字符串中是否包含我们设想的Exception内容即可。

坚持原创技术分享,您的支持将鼓励我继续创作!