如何在Python单元测试中模拟time.sleep()

32 投票
6 回答
42891 浏览
提问于 2025-04-18 01:09

我想做一个简单的替代方法,来阻止time.sleep(..)这个函数让程序暂停,以此来提高单元测试的执行速度。

我现在有的代码是:

import time as orgtime

class time(orgtime):
    '''Stub for time.'''
    _sleep_speed_factor = 1.0

    @staticmethod
    def _set_sleep_speed_factor(sleep_speed_factor):
        '''Sets sleep speed.'''
        time._sleep_speed_factor = sleep_speed_factor


    @staticmethod
    def sleep(duration):
        '''Sleeps or not.'''
        print duration * time._sleep_speed_factor
        super.sleep(duration * time._sleep_speed_factor) 

但是,在上面第二行代码(类定义)时,我遇到了以下错误:

TypeError: Error when calling the metaclass bases
module.__init__() takes at most 2 arguments (3 given).

怎么解决这个错误呢?

6 个回答

3

那这个怎么样:

import time
from time import sleep as originalsleep

def newsleep(seconds):
    sleep_speed_factor = 10.0 
    originalsleep(seconds/sleep_speed_factor)

time.sleep = newsleep

这个对我有效。我把它放在我想加速的测试开始部分,最后再把原来的延迟设置回去,以防万一。希望这能帮到你。

7

这是我为了防止测试过程中出现暂停的情况所做的:

假设我有一个模块叫做 mymodule.py,里面有一个函数使用了 sleep,而我想对这个函数进行测试:

from time import sleep

def some_func()
    sleep(5)
    # ...do some things

接着,我在测试中从使用 sleep 的模块中导入它,像这样:

@mock.patch('mymodule.sleep')
def test_some_func(mock_sleep):
    mock_sleep.return_value = None
    # ...continue my test
16

我正在使用 pytest,并且有一个用于修改 time.sleep 的工具:

import pytest


@pytest.fixture
def sleepless(monkeypatch):

    def sleep(seconds):
        pass

    monkeypatch.setattr(time, 'sleep', sleep)

然后在我需要“加速”睡眠的测试中,我只需使用这个工具:

import time

def test_sleep(sleepless):
    time.sleep(60)

所以当你运行这个测试时,你会发现它完成的时间要短得多:

= 1 passed in 0.02 seconds =
19

被认可的答案仍然有效。不过,从Python 3.3开始,unittest.mock已经成为Python标准库的官方组成部分。

import time
from unittest import TestCase
from unittest.mock import patch

class TestMyCase(TestCase):

    @patch('time.sleep', return_value=None)
    def test_my_method(self, patched_time_sleep):
        time.sleep(60)  # Should be instant

        # the mock should only be called once
        self.assertEqual(1, patched_time_sleep.call_count)
        # or 
        patched_time_sleep.assert_called_once()

    # alternative version using a context manager
    def test_my_method_alternative(self):
        with patch('time.sleep', return_value=None) as patched_time_sleep:
            time.sleep(60)  # Should be instant

        # the mock should only be called once
        self.assertEqual(1, patched_time_sleep.call_count)
        # or 
        patched_time_sleep.assert_called_once()
53

你可以在测试中使用 mock 这个库。

import time
from mock import patch

class MyTestCase(...):


     @patch('time.sleep', return_value=None)
     def my_test(self, patched_time_sleep):
          time.sleep(666)  # Should be instant

撰写回答