移动端自动化测试系列之二——pytest入门详解

pytest教程

Posted by Mio4kon on 2017-04-12

前言

pytest是一个方便去写测试用例的测试框架.由于一开始我也不太清楚python有哪些比较好的测试框架,所以在写框架之前先调研了一些常见的测试框架.

  • Unittest
  • Doctest
  • pytest
  • nose

最终我倾向于nosepytest,在进一步的了解这两款测试框架的api之后,最终选用了pytest,原因是使用起来真的非常简单.而且对Allure支持的非常好,这是后话了.我们先来看看pytest到底怎么使用吧.

这里我使用的IDE是:pycharm,非常好用.建议下载一个使用.尤其是对应python新手.

pytest 安装

pip3 install pytest

或者设置Pycharm的工程解释器来安装

进入Preferences:

pytest 使用

sample-run

创建一个 sample.py 文件

1
2
3
# content of sample.py
def test_answer():
assert 1 + 2 == 3

执行

py.test sample.py
或者
pytest sample.py

可以发现用例执行成功.

上述命令可以使pytest自动查找 sample.py 文件下所有的格式为:test_*的方法,然后执行用例.执行顺序为方法的顺序.

如果有多个py文件,可以直接使用下面命令

pytest

这个命令会找出当前目录下所有格式为test_*.py*_test.py的文件然后执行用例.上面我们定义的文件名为sample.py,所以如果使用pytest是找不到用例的,我们需要把名称改成test_sample.py或者sample_test.py

注意文件内的方法名必须是test_*这种类型.如果写成def answer_test() 也是找不到的.
查找规则见文档: test-discovery

输出日志

在测试用例中输出日志,是常见的场景,如下

1
2
3
4
5
# content of test_sample.py
class TestSample:
def test_answer(self):
print('this is a log')
assert 1 + 2 == 3

然后执行py.test sample.py是不会输出日志的.需要加上-s参数.同时建议也加上-q参数.即quiet 报道模式,这样输出会好看点.

pytest test_sample.py -s -q

fixtures

说到测试框架自然要说到setup和teardown两个方法.

  • setup是用来做准备操作.一般用来初始化资源.
  • teardown是用来做收尾操作.一般用了关闭资源.

pytest的setupteardown是利用@pytest.fixture这个注释来完成的.不仅可以完成初始化操作,初始化后如果有数据需要给用例使用也是非常方便!

setup

直接来看下面代码.

1
2
3
4
5
6
7
8
9
10
11
# content of test_sample.py
import pytest
class TestSample:
@pytest.fixture()
def count(self):
print('init count')
return 10
def test_answer(self, count):
print('get count %s' % count)
assert count == 10

执行结果:

通过@pytest.fixture() 注释会在执行测试用例之前初始化操作.然后直接在测试用例的方法中就可以拿到初始化返回的参数(参数名要和初始化的方法名一样)

OK,假如我们新增一个方法会怎么样?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# content of test_sample.py
import pytest
class TestSample:
@pytest.fixture()
def count(self):
print('init count')
return 10
def test_answer(self, count):
print('test_answer get count %s' % count)
assert count == 10
def test_answer_2(self, count):
print('test_answer_2 get count %s' % count)
assert count == 10

可以发现 init count 这条日志输出两遍,也就是执行了两次初始化.这并没有什么问题.但是有时候我们希望的一个全局的初始化,既我们希望在这个类中只会执行一次这个初始化该怎么做?

fixture 有一个域(scope)的概念,用来指定该 fixture 的使用范围.

这里有五种域: module/class/session/invocation/function(default).

为了简单测试,这里我们修改一下工程目录结构,并且把fixture专门放到一个文件中方便使用:

通过下面命令可以列出当前目录中查找出来的所有 fixture

pytest --fixtures
或者
pytest --fixtures [目录]

这里有个坑,就是虽然这里发现了 count 这个fixture,但在跑case的时候会报错说找不到!

原因是写 fixture 的文件的文件名不能瞎比写啊(捂脸),必须叫做 conftest.py

改完文件名后我们在运行:

这是在使用 seesion 域的情况下,可以发现init只执行一次.假如我们需要这种情况,每一个类都执行一次init,那么很简单直接把域改成 class 即可,同理 module 是基于模块的.有兴趣可以都去尝试一下.这里就不细说了.

teardown

利用python 的语法 yield 即可.

1
2
3
4
5
6
7
# content of conftest.py
import pytest
@pytest.fixture(scope="session")
def count():
print('init count')
yield 10
print('teardown count')

执行结果

代码中执行用例

有些时候需要在代码中调用执行case的方法.而不是通过command的方式.我们可以在python代码中加入下面代码即可:

args = ['-s', '-q']
pytest.main(args)

参考文档

如果上述内容消化完后,那么测试框架的使用已经没有什么问题了.如果还需要了解其他的特性,可以参考官网文档.

https://docs.pytest.org/en/latest/contents.html