关于单元测试:如何为python单元测试指定测试超时?

How to specify test timeout for python unittest?

我使用的是python框架unittest。是否可以根据框架的能力指定测试超时?如果没有,是否可以为所有测试和一些单独的测试分别指定一个timeout值?我想为所有测试定义一个global timeout(默认情况下,它们将使用它),并为一些可能需要很长时间的测试定义一个超时。


据我所知,unittest不包含对测试超时的任何支持。

您可以从pypi中尝试timeout-decorator库。在单个测试上应用decorator,使它们在使用时间过长时终止:

1
2
3
4
5
6
7
8
9
10
11
import timeout_decorator

class TestCaseWithTimeouts(unittest.TestCase):

    # ... whatever ...

    @timeout_decorator.timeout(LOCAL_TIMEOUT)
    def test_that_can_take_too_long(self):
        sleep(float('inf'))

    # ... whatever else ...

要创建全局超时,可以替换调用

1
unittest.main()

具有

1
timeout_decorator.timeout(GLOBAL_TIMEOUT)(unittest.main)()


基于这个答案,我使用withkeyowrd构建了一个unittest超时解决方案。

这种方法也使用signal,因此它可能只在*nix系统上有效(我只在我的Ubuntu16.04环境中运行)。

  • 导入信号,添加一个TestTimeout例外:
  • 1
    2
    3
    4
    5
    6
    import signal

    ...

    class TestTimeout(Exception):
        pass
  • 定义类test_timeout,它将处理with块:
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class test_timeout:
      def __init__(self, seconds, error_message=None):
        if error_message is None:
          error_message = 'test timed out after {}s.'.format(seconds)
        self.seconds = seconds
        self.error_message = error_message

      def handle_timeout(self, signum, frame):
        raise TestTimeout(self.error_message)

      def __enter__(self):
        signal.signal(signal.SIGALRM, self.handle_timeout)
        signal.alarm(self.seconds)

      def __exit__(self, exc_type, exc_val, exc_tb):
        signal.alarm(0)
  • 在单元测试中嵌入with test_timeout()块:
  • 1
    2
    3
    def test_foo(self):
      with test_timeout(5):  # test has 5 seconds to complete
        ... foo unit test code ...

    使用这种方法,超时的测试将由于引发TestTimeout异常而导致错误。

    或者,您可以将with test_timeout()块包装在try: except TestTimeout:块中,并以更高的粒度处理异常(例如跳过测试而不是错误)。