Как отключить time.sleep() в модульном тестировании Python

Я хочу сделать заглушку, чтобы предотвратить sleep.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).

Как исправить ошибку?

Ответ 1

Вы можете использовать макет библиотеки в своих тестах.

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

Ответ 2

Как насчет:

import time
from time import sleep as originalsleep

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

time.sleep = newsleep

Это работает для меня. Я рассказываю об этом в начале теста, который я хочу ускорить, в конце я вернул исходный сон на всякий случай. Надеюсь, поможет

Ответ 3

использование пакета freezegun может помочь вам в этом.

# fake.py
import functools
from datetime import datetime, timedelta
from unittest import mock

from freezegun import freeze_time


def fake_sleep(func):
    freezegun_control = None

    def fake_sleep(seconds):
        nonlocal freezegun_control
        utcnow = datetime.utcnow()
        if freezegun_control is not None:
            freezegun_control.stop()
        freezegun_control = freeze_time(utcnow + timedelta(seconds=seconds))
        freezegun_control.start()

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        with mock.patch('time.sleep', fake_sleep):
            rv = func(*args, **kwargs)

            if freezegun_control is not None:
                freezegun_control.stop()
            return rv

    return wrapper


# test.py
from fake import fake_sleep

import time

@fake_sleep
def test_sleep():
    now = datetime.utcnow()

    for sleep_seconds in range(10):
        for i in range(1, 10):

            time.sleep(sleep_seconds)

            assert datetime.utcnow() - now >= timedelta(
                seconds=i * sleep_seconds)
  1. общая демонстрация: см. freezegun README
  2. pytest demo: функция поддельного сна с функцией Gist

Ответ 4

Принятый ответ остается в силе. Однако, начиная с 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)

    # 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)