首页 > 解决方案 > Django 分析测试

问题描述

所以我发现这篇2016 年的文章详细介绍了如何创建一个自定义测试运行器来捕获在 Django 中运行测试所需的时间:

亚军.py:

from unittest.runner import TextTestResult
from django.test.runner import DiscoverRunner

import time

class TimeLoggingTestRunner(DiscoverRunner):
    def __init__(self, slow_test_threshold=0.0, *args, **kwargs):
        self.slow_test_threshold = slow_test_threshold
        return super().__init__(
            resultclass=TimeLoggingTestResult,
            *args,
            **kwargs,
        )
    def run(self, test):
        result = super().run(test)
        self.stream.writeln(
            "\nSlow Tests (>{:.03}s):".format(
                self.slow_test_threshold))
        for name, elapsed in result.getTestTimings():
            if elapsed > self.slow_test_threshold:
                self.stream.writeln(
                    "({:.03}s) {}".format(
                        elapsed, name))
        return result

    def get_resultclass(self):
        return TimeLoggingTestResult

class TimeLoggingTestResult(TextTestResult):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.test_timings = []
    def startTest(self, test):
        self._test_started_at = time.time()
        super().startTest(test)
    def addSuccess(self, test):
        elapsed = time.time() - self._test_started_at
        name = self.getDescription(test)
        self.test_timings.append((name, elapsed))
        super().addSuccess(test)
    def getTestTimings(self):
        return self.test_timings

设置.py:

TEST_RUNNER = 'core.utils.test_runner.runner.TimeLoggingTestRunner'

但是,最后没有打印任何内容。我知道代码会运行,因为调试语句在两个类中都会触发 - 但实际的最终结果 ( run) 似乎没有被调用。

我设法做的是获得打印时间(通过在里面添加打印语句TimeLoggingTestResult),但我似乎无法让它们在最后全部打印出来。

有没有人有做这样的事情的经验?该run方法似乎根本无法访问。

使用 Django 1.11。

标签: pythondjangopython-unittest

解决方案


我知道这是一个老问题,但我发现它是为了寻找一种方法来分析我的测试并尝试自己实现它。我在 Django 3.0.8 上,但遇到了与提问者相同的问题。

经过研究,我发现DiscoverRunner它不是从 TextTestRunner 继承的,它使用组合。而不是调用self.run()它调用runner.run(). 请参阅下面的代码。

class DiscoverRunner:
    ...
    test_runner = unittest.TextTestRunner
    ...
    def run_suite(self, suite, **kwargs):
        kwargs = self.get_test_runner_kwargs()
        runner = self.test_runner(**kwargs)
        return runner.run(suite)

我所做的是TimeLoggingTestRunner继承 DiscoverRunner 和 TextTestRunner 并覆盖run_suite().

class TimeLoggingTestRunner(DiscoverRunner, TextTestRunner):
    def __init__(self, *args, slow_test_threshold=0.0, **kwargs):
        self.slow_test_threshold = slow_test_threshold
        DiscoverRunner.__init__(self, *args, **kwargs)
        TextTestRunner.__init__(self, *args, **self.get_test_runner_kwargs())
    [...]
    def run_suite(self, suite, **kwargs):
        return self.run(suite)

可能有更好的方法来处理继承,但它正在工作。

另一种选择可能是创建两个 TestRunner,分别继承 DiscoverRunner 和 TextTestRunner,然后以与 DiscoverRunner 相同的方式组合它们。


推荐阅读