11

此问题类似,我想让 Nose 运行一次测试(或所有测试)n次——但不是并行运行。

我在一个项目中有几百个测试;有些是一些简单的单元测试。其他的是具有某种程度的并发性的集成测试。经常在调试测试时,我想更努力地“打”一个测试;一个 bash 循环可以工作,但会产生很多杂乱的输出——不再是漂亮的单个“。” 每次通过测试。有能力在选定的测试中击败一些试验似乎是要求 Nose 做的一件自然的事情,但我在文档中的任何地方都没有找到它。

让 Nose 执行此操作的最简单方法是什么(除了 bash 循环)?

4

5 回答 5

17

您可以将鼻子测试编写为生成器,然后鼻子将运行产生的每个函数:

def check_something(arg):
    # some test ...

def test_something():
    for arg in some_sequence:
        yield (check_something, arg)

使用nose-testconfig,您可以将测试运行次数设为命令行参数:

from testconfig import config

# ...

def test_something():
    for n in range(int(config.get("runs", 1))):
        yield (check_something, arg)

你会从命令行调用它,例如

$ nosetests --tc=runs:5

...不止一次运行。

或者(但也使用nose-testconfig),您可以编写一个装饰器:

from functools import wraps
from testconfig import config

def multi(fn):
    @wraps(fn)
    def wrapper():
        for n in range(int(config.get("runs", 1))):
            fn()
    return wrapper

@multi
def test_something():
    # some test ...

然后,如果您想将测试分成不同的组,每个组都有自己的运行次数命令行参数:

from functools import wraps
from testconfig import config

def multi(cmd_line_arg):
    def wrap(fn):
        @wraps(fn)
        def wrapper():
            for n in range(int(config.get(cmd_line_arg, 1))):
                fn()
        return wrapper
    return wrap

@multi("foo")
def test_something():
    # some test ...

@multi("bar")
def test_something_else():
    # some test ...

你可以这样称呼它:

$ nosetests --tc=foo:3 --tc=bar:7
于 2012-11-28T18:18:40.390 回答
3

您必须编写一个脚本来执行此操作,但您可以在命令行上重复测试名称 X 次。

nosetests testname testname testname testname testname testname testname

等等

于 2014-05-30T00:25:24.733 回答
3

我最终使用的解决方案是创建 sh 脚本 run_test.sh:

var=0
while $1; do
    ((var++))
    echo "*** RETRY $var"
done

用法:

./run_test.sh "nosetests TestName"

它无限运行测试,但在第一个错误时停止。

于 2015-06-18T11:47:50.380 回答
2

一种方法是在测试本身:

改变这个:

class MyTest(unittest.TestCase):

  def test_once(self):
      ...

对此:

class MyTest(unittest.TestCase):

  def assert_once(self):
      ...

  def test_many(self):
      for _ in range(5):
          self.assert_once()
于 2012-11-28T18:19:16.377 回答
-1

永远不应该有理由多次运行测试。重要的是您的测试是确定性的(即给定代码库的相同状态,它们总是产生相同的结果。)如果不是这种情况,那么您应该重新设计测试和/或,而不是多次运行测试代码,这样他们就可以了。

例如,测试间歇性失败的一个原因是测试和被测代码 (CUT) 之间的竞争条件。在这种情况下,一个天真的反应是在测试中添加一个大的“巫毒睡眠”,以“确保”在测试开始断言之前完成 CUT。

但是,这很容易出错,因为如果您的 CUT 由于任何原因(硬件功率不足、加载的盒子、繁忙的数据库等)很慢,那么它会偶尔失败。在这种情况下,更好的解决方案是让您的测试等待事件,而不是休眠。

该事件可以是您选择的任何内容。有时,已经生成了您可以使用的事件(例如,Javascript DOM 事件,Selenium 测试可以使用的“pageRendered”类型的事件。)其他时候,您可能适合向 CUT 添加代码,这会引发完成后的事件(也许您的架构涉及对此类事件感兴趣的其他组件。)

但是,您通常需要重新编写测试,以便它尝试检测您的 CUT 是否已完成执行(例如,输出文件是否存在?),如果不存在,则休眠 50 毫秒,然后重试。最终它会超时并失败,但只有在很长一段时间后才会这样做(例如,你的 CUT 的预期执行时间的 100 倍)

另一种方法是使用'onion/hexagonal/ports'n'adaptors'原则设计你的CUT,它坚持你的业务逻辑应该没有所有外部依赖。这意味着您的业务逻辑可以使用普通的亚毫秒单元测试进行测试,它永远不会触及网络或文件系统。完成此操作后,您需要的端到端系统测试要少得多,因为它们现在就像集成测试一样,不需要尝试通过 UI 处理业务逻辑的每个细节和边缘案例. 这种方法还将在其他领域产生巨大的好处,例如改进的 CUT 设计(减少组件之间的依赖关系),测试更容易编写,运行整个测试套件的时间大大减少。

使用上述方法可以完全消除测试不可靠的问题,我建议这样做,不仅可以改善您的测试,还可以改善您的代码库和设计能力。

于 2012-11-28T18:20:57.267 回答