Mat*_*Moy 5 python testing unit-testing
大多数测试框架都假设“1 个测试 = 1 个 Python 方法/函数”,并认为当函数执行时没有提出断言,测试就通过了。
我正在测试一个类似编译器的程序(一个读取*.foo
文件并处理其内容的程序),我想对许多输入 ( *.foo) 文件执行相同的测试。IOW,我的测试看起来像:
class Test(unittest.TestCase):
def one_file(self, filename):
# do the actual test
def list_testcases(self):
# essentially os.listdir('tests/') and filter *.foo files.
def test_all(self):
for f in self.list_testcases():
one_file(f)
Run Code Online (Sandbox Code Playgroud)
我当前的代码使用
Python 标准库中的unittest,即one_file使用self.assert...(...)
语句来检查测试是否通过。
这是有效的,因为当我的代码正常/有问题时,我确实得到了一个成功/失败的程序,但是我失去了测试框架的许多优点:
我没有得到相关的报告,比如“Y 次测试中的 X 次失败”,也没有通过/失败的测试列表。(我打算使用这样的系统不仅测试我自己的开发,还作为老师对学生的代码进行评分,所以报告对我很重要)
我没有测试独立性。第二个测试在第一个测试留下的环境上运行,依此类推。第一次失败会停止测试套件:根本不会运行失败后的测试用例。
我觉得我在滥用我的测试框架:只有一个测试功能,因此 unittest 的自动测试发现听起来有点矫枉过正。相同的代码可以(应该?)用简单的 Python 编写,并带有基本的assert.
一个明显的替代方法是将我的代码更改为类似
class Test(unittest.TestCase):
def one_file(self, filename):
# do the actual test
def test_file1(self):
one_file("first-testcase.foo")
def test_file2(self):
one_file("second-testcase.foo")
Run Code Online (Sandbox Code Playgroud)
然后我得到了 unittest 的所有优点,但是:
要编写的代码要多得多。
很容易“忘记”一个测试用例,即在其中创建一个测试文件
tests/而忘记将其添加到 Python 测试中。
我可以想象一个解决方案,我会动态地为每个测试用例生成一个方法(沿着 setattr(self, 'test_file' + str(n), ...)),以便为第二个解决方案生成代码,而无需手动编写。但是对于一个看起来并不那么复杂的用例来说,这听起来真的有点过分了。
我怎样才能充分利用两者,即自动测试用例发现(列表tests/*.foo文件)、测试独立性和正确的报告?
如果您可以使用pytest作为测试运行器,那么使用parametrize装饰器实际上非常简单:
import pytest, glob
all_files = glob.glob('some/path/*.foo')
@pytest.mark.parametrize('filename', all_files)
def test_one_file(filename):
# do the actual test
Run Code Online (Sandbox Code Playgroud)
这还将以有用的方式自动命名测试,以便您可以查看哪些文件失败了:
$ py.test
================================== test session starts ===================================
platform darwin -- Python 3.6.1, pytest-3.1.3, py-1.4.34, pluggy-0.4.0
[...]
======================================== FAILURES ========================================
_____________________________ test_one_file[some/path/a.foo] _____________________________
filename = 'some/path/a.foo'
@pytest.mark.parametrize('filename', all_files)
def test_one_file(filename):
> assert False
E assert False
test_it.py:7: AssertionError
_____________________________ test_one_file[some/path/b.foo] _____________________________
filename = 'some/path/b.foo'
@pytest.mark.parametrize('filename', all_files)
def test_one_file(filename):
[...]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
906 次 |
| 最近记录: |