由于 Django 使用 python 的标准 unittest 库,您必须调整它的一些部分。
首先,您需要一些方法来指定哪些测试实际测试哪个端点。自定义装饰器很方便:
from functools import wraps
def endpoint(path, code):
"""
Mark some test as one which tests specific endpoint.
"""
def inner(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
inner._endpoint_path = path
inner._endpoint_code = code
return inner
class MyTestCase(TestCase):
@endpoint(path='/path/one', code=200)
def test_my_path_is_ok(self):
response = self.client.get('/path/one?foo=bar')
self.assertEqual(response.status_code, 200)
@endpoint(path='/path/one', code=404)
def test_my_path_expected_errors(self):
response = self.client.get('/path/one?foo=qux')
self.assertEqual(response.status_code, 404)
def test_some_other_stuff(self):
# this one will not be included in our results grid.
pass
您可以使用“神奇”的方法(例如,特殊方法的名称来猜测它们正在测试的端点),但是 explicit is better than implicit,对吗?
那么,您需要一种方法来收集测试结果 - 特别是测试端点的结果。在这里,我们创建了一个(非常草稿)unittest.TestResult 的子类来处理它:
class EndpointsTestResult(TestResult):
def __init__(self):
super(EndpointsTestResult, self).__init__()
self.endpoint_results = {}
def addError(self, test, err):
super(EndpointsTestResult, self).addError(test, err)
if hasattr(test, '_endpoint_path'):
branch = self.endpoint_results.setdefault(getattr(test, '_endpoint_path'), {})
branch[getattr(test, '_endpoint_code')] = 'MISSING'
def addFailure(self, test, err):
# similar as addError()
def addSuccess(self, test):
# similar as addError()
最后是时候实际输出我们的结果了。让我们创建一个 unittest.TextTestRunner 的子类并在我们的自定义运行器中指定它:
class EndpointsTestRunner(TextTestRunner):
def _makeResult(self):
self._result = EndpointsTestResult()
return self._result
def run(self, test):
super(EndpointsTestRunner).run(test)
# After running a test, print out the table
generate_a_nifty_table(self._result.endpoint_results)
class EndpointsDjangoRunner(django.test.runner.DiscoverRunner):
test_runner = EndpointsTestRunner
现在我们有了自定义的EndpointsDjangoRunner,我们应该在settings.py 中指定它:
TEST_RUNNER = 'path.to.the.EndpointsDjangoRunner'
就是这样。如果您在代码中发现任何尴尬的错误,请告诉我。