如何在Python中无须增加代码来基准测试单元测试
我有一个Python项目,里面已经写了一堆测试,现在我想开始对这些测试进行基准测试,这样我就可以比较代码、服务器等在一段时间内的性能。找到这些测试文件其实不难,因为我所有的测试文件名里都有“test”这个词。不过,我在尝试动态执行这些测试时遇到了一些麻烦。
目前,我能运行一个脚本,这个脚本接受一个目录路径作为参数,然后返回一个文件路径的列表,像这样:
def getTestFiles(directory):
fileList = []
print "Searching for 'test' in " + directory
if not os.path.isdir(os.path.dirname(directory)):
# throw error
raise InputError(directory, "Not a valid directory")
else:
for root, dirs, files in os.walk(directory):
#print files
for f in files:
if "test" in f and f.endswith(".py"):
fileList.append(os.path.join(root, f))
return fileList
# returns a list like this:
# [ 'C:/Users/myName/Desktop/example1_test.py',
# 'C:/Users/myName/Desktop/example2_test.py',
# 'C:/Users/myName/Desktop/folder1/example3_test.py',
# 'C:/Users/myName/Desktop/folder2/example4_test.py'... ]
问题是,这些文件的语法可能不同,我正在想办法处理这个问题。例如:
TestExampleOne:
import dummy1
import dummy2
import dummy3
class TestExampleOne(unittest.TestCase):
@classmethod
def setUpClass(cls):
# set up
def test_one(self):
# test stuff
def test_two(self):
# test stuff
def test_three(self):
# test stuff
# etc...
TestExampleTwo:
import dummy1
import dummy2
import dummy3
def setup(self):
try:
# config stuff
except Exception as e:
logger.exception(e)
def test_one():
# test stuff
def test_two():
# test stuff
def test_three():
# test stuff
# etc...
TestExampleThree:
import dummy1
import dummy2
import dummy3
def setup(self):
try:
# config stuff
except Exception as e:
logger.exception(e)
class TestExampleTwo(unittest.TestCase):
def test_one(self):
# test stuff
def test_two(self):
# test stuff
# etc...
class TestExampleThree(unittest.TestCase):
def test_one(self):
# test stuff
def test_two(self):
# test stuff
# etc...
# etc...
我真的希望能写一个模块,去搜索一个目录,找到所有文件名里包含“test”的文件,然后执行每个文件里的每个单元测试,并提供每个测试的执行时间。我觉得像NodeVisitor这样的东西可能是个不错的方向,但我不太确定。即使是一个开始的想法也会非常感谢。谢谢!
1 个回答
使用 nose
测试工具可以帮助我们 发现测试,以及设置和清理函数。
nose-timer
插件可以帮助我们进行性能测试:
这是一个用于 nosetests 的计时插件,能回答一个问题:每个测试花费了多少时间?
演示:
假设你有一个名为
test_nose
的包,里面有以下脚本:test1.py
:import time import unittest class TestExampleOne(unittest.TestCase): @classmethod def setUpClass(cls): cls.value = 1 def test_one(self): time.sleep(1) self.assertEqual(1, self.value)
test2.py
:import time value = None def setup(): global value value = 1 def test_one(): time.sleep(2) assert value == 1
test3.py
:import time import unittest value = None def setup(): global value value = 1 class TestExampleTwo(unittest.TestCase): def test_one(self): time.sleep(3) self.assertEqual(1, value) class TestExampleThree(unittest.TestCase): def test_one(self): time.sleep(4) self.assertEqual(1, value)
安装
nose
测试工具:pip install nose
安装
nose-timer
插件:pip install nose-timer
运行测试:
$ nosetests test_nose --with-timer .... test_nose.test3.TestExampleThree.test_one: 4.0003s test_nose.test3.TestExampleTwo.test_one: 3.0010s test_nose.test2.test_one: 2.0011s test_nose.test1.TestExampleOne.test_one: 1.0005s ---------------------------------------------------------------------- Ran 4 tests in 10.006s OK
结果会很方便地被高亮显示:

颜色可以通过 --timer-ok
和 --timer-warning
参数来控制。
注意,time.sleep(n)
的调用是为了手动增加延迟,以便清楚地看到影响。同时,value
变量在 "setup" 函数和方法中被设置为 1
,然后在测试函数和方法中,value
被断言为 1
- 这样你就可以看到设置函数的工作效果。
更新(从脚本中运行 nose
和 nose-timer
):
from pprint import pprint
import nose
from nosetimer import plugin
plugin = plugin.TimerPlugin()
plugin.enabled = True
plugin.timer_ok = 1000
plugin.timer_warning = 2000
plugin.timer_no_color = False
nose.run(plugins=[plugin])
result = plugin._timed_tests
pprint(result)
将其保存到 test.py
脚本中,并传入目标目录:
python test.py /home/example/dir/tests --with-timer
result
变量将包含:
{'test_nose.test1.TestExampleOne.test_one': 1.0009748935699463,
'test_nose.test2.test_one': 2.0003929138183594,
'test_nose.test3.TestExampleThree.test_one': 4.000233173370361,
'test_nose.test3.TestExampleTwo.test_one': 3.001115083694458}