如何衡量每个django测试的时间曲线?

时间:2016-09-28 05:55:28

标签: django unit-testing profiling

我想测量每个测试用例运行所需的(墙?)时间。

我想在一个timeit中包装test_runner会完成这项工作,但在我潜入那个兔子洞之前,也许还有一种更聪明的方法可以做到这一点?

这已经给了我一个cProfile来弥补,但没有什么真正跳出来的可怕的糟糕。我想也许我的时间可以集中在那些运行时间最长的那些。

time python -m cProfile -o keep-p4-serialize.profile manage.py test -v 3 -k --parallel 4

例如:

test_dependencies (api.tests.TestMetricClasses) ... ok (4.003s)
test_metrics (api.tests.TestMetricClasses) ... ok (8.329s)
test_parameters (api.tests.TestMetricClasses) ... ok (0.001s)

3 个答案:

答案 0 :(得分:4)

这足以让我(相对时间),但它并不适用于并行运行的测试,并且肯定有提高时间准确性的余地。尽管如此:

通过settings.py覆盖默认参赛者:

TEST_RUNNER = 'myapp.test_runner.MyTestRunner'

从而创建自己的test_runner myapp/test_runner.py

from django.test.runner import DiscoverRunner

class MyTestRunner(DiscoverRunner):
    test_runner = TimedTextTestRunner

反过来,覆盖结果类:

from unittest.runner import TextTestRunner, TextTestResult

class TimedTextTestRunner(TextTestRunner):
    resultclass = TimedTextTestResult

现在结果对象不只是一个结果而是很多,所以我们需要一组时钟,通过测试键入。然后捕获测试开始的时间并打印出打印成功字符串时经过的时间:

class TimedTextTestResult(TextTestResult):

    def __init__(self, *args, **kwargs):
        super(TimedTextTestResult, self).__init__(*args, **kwargs)
        self.clocks = dict()

    def startTest(self, test):
        self.clocks[test] = time()
        super(TextTestResult, self).startTest(test)
        if self.showAll:
            self.stream.write(self.getDescription(test))
            self.stream.write(" ... ")
            self.stream.flush()

    def addSuccess(self, test):
        super(TextTestResult, self).addSuccess(test)
        if self.showAll:
            self.stream.writeln("ok-dokey (%.6fs)" % (time() - self.clocks[test]))
        elif self.dots:
            self.stream.write('.')
            self.stream.flush()

这给了我看起来像这样的测试报告:

test_price_impact (api.tests.TestGroupViews) ... ok-dokey (3.123600s)
test_realised_spread (api.tests.TestGroupViews) ... ok-dokey (6.894571s)
test_sqrt_trade_value (api.tests.TestGroupViews) ... ok-dokey (0.147969s)
test_trade_count_share (api.tests.TestGroupViews) ... ok-dokey (3.124844s)
test_trade_size (api.tests.TestGroupViews) ... ok-dokey (3.134234s)
test_value_share (api.tests.TestGroupViews) ... ok-dokey (2.939364s)

答案 1 :(得分:2)

nose有一个计时器插件,它记录每次单个测试执行的挂起时间。

https://github.com/mahmoudimus/nose-timer/tree/master/nosetimer

Nose的coberatura xml报告还默认显示每次测试所花费的时间。

对于django特定问题,可以通过一些简单的优化来增加测试的运行时间:

  • 如果您没有使用特定于数据库的功能,请使用Sqlite
  • 使用md5密码哈希,(或根本没有密码哈希)
  • 禁用迁移
  • 删除io,尽可能地隔离逻辑,这样可以避免创建复杂的模型依赖关系

test_dependenciestest_metrics中有多少项测试?它们中有哪些类型的测试?

答案 2 :(得分:0)

一个老问题,但我碰到它,发现没有提到django-slowtest,我认为这绝对值得一提。我已经使用了很长一段时间了,我对结果非常满意。唯一的缺点是,它尚未声明它正式支持Django> = 2 ,但是我没有遇到任何问题,并且由于它仅在我身上开发,因此我可以放心使用它。

  • --parallel上正常工作
  • 可以配置要在运行测试后显示多少个慢速测试
  • 在将测试标记为slow时可以在阈值中配置
  • 具有报告(导出)功能。
  • 截至2019年2月仍保持不变

https://github.com/realpython/django-slow-tests

来自文档: 安装:

$ pip install django-slowtests

添加以下设置:

TEST_RUNNER = 'django_slowtests.testrunner.DiscoverSlowestTestsRunner'
NUM_SLOW_TESTS = 10

# (Optional)
SLOW_TEST_THRESHOLD_MS = 200  # Only show tests slower than 200ms

# (Optional)
ALWAYS_GENERATE_SLOW_REPORT = False  # Generate report only when requested using --slowreport flag

最后,运行测试

$ python manage.py test
Creating test database for alias 'default'...
..........
----------------------------------------------------------------------
Ran 10 tests in 0.413s

OK
Destroying test database for alias 'default'...

Ten slowest tests:
0.3597s test_detail_view_with_a_future_poll (polls.tests.PollIndexDetailTests)
0.0284s test_detail_view_with_a_past_poll (polls.tests.PollIndexDetailTests)
0.0068s test_index_view_with_a_future_poll (polls.tests.PollViewTests)
0.0047s test_index_view_with_a_past_poll (polls.tests.PollViewTests)
0.0045s test_index_view_with_two_past_polls (polls.tests.PollViewTests)
0.0041s test_index_view_with_future_poll_and_past_poll (polls.tests.PollViewTests)
0.0036s test_index_view_with_no_polls (polls.tests.PollViewTests)
0.0003s test_was_published_recently_with_future_poll (polls.tests.PollMethodTests)
0.0002s test_was_published_recently_with_recent_poll (polls.tests.PollMethodTests)
0.0002s test_was_published_recently_with_old_poll (polls.tests.PollMethodTests)