在 Python 中寻找片状测试的根本原因

gue*_*tli 8 python trace unit-testing pytest

有一个不稳定的测试,我们不知道根本原因可能是什么。

with pytest.raises(foo.geocoder.GeocodingFailed):
    foo.geocoder.geocode('not a valid place')
Run Code Online (Sandbox Code Playgroud)

有时异常不会发生。

我查看了如何处理失败的文档,但这并没有帮助。

如何跟踪geocode()以便如果异常没有发生,我会看到跟踪?

我查看trace了标准库的模块。但是似乎没有简单的方法可以将跟踪作为字符串获取。

“跟踪”我的意思是:在gecode(). 我想查看带有缩进的方法调用和返回语句。我想忽略 Python 标准库中的行。

AFAIK 像 pdb 这样的调试器在这里没有帮助,因为测试仅在 CI 中运行时才会失败,并且每个月只有一次或两次。

Niz*_*med 4

trace模块通过类提供编程访问trace.Trace
测试失败时,Trace类的控制台输出可见。
它有覆盖报告可写在所选路径上。

我排除sys.base_exec_prefix,sys.base_prefix以免跟踪 Python 库模块。

import pytest


def f(x):
    import random

    choice = random.choice((True, False))

    if choice:
        raise ValueError
    else:
        return x * 2


def trace(f, *args, **kwargs):
    import trace
    import sys

    tracer = trace.Trace(
        ignoredirs=(sys.base_exec_prefix, sys.base_prefix), timing=True,
    )
    ret = tracer.runfunc(f, *args, **kwargs)
    r = tracer.results()
    r.write_results(coverdir="/tmp/xx-trace")
    return ret


def test_f():
    with pytest.raises(ValueError):
        trace(f, 3)
Run Code Online (Sandbox Code Playgroud)

pytest运行

覆盖率报告;
标有 >>>>>> 的行未执行,即未跟踪,带冒号的数字是执行计数。

>>>>>> import pytest
       
       
>>>>>> def f(x):
    1:     import random
       
    1:     choice = random.choice((True, False))
       
    1:     if choice:
>>>>>>         raise ValueError
           else:
    1:         return x * 2
       
       
>>>>>> def trace(f, *args, **kwargs):
>>>>>>     import trace
>>>>>>     import sys
       
>>>>>>     tracer = trace.Trace(
>>>>>>         ignoredirs=(sys.base_exec_prefix, sys.base_prefix), timing=True,
           )
>>>>>>     tracer.runfunc(f, *args, **kwargs)
>>>>>>     r = tracer.results()
>>>>>>     r.write_results(coverdir="/tmp/xx-trace")
       
       
>>>>>> def test_f():
>>>>>>     with pytest.raises(ValueError):
>>>>>>         trace(f, 3)
Run Code Online (Sandbox Code Playgroud)