web-dev-qa-db-ja.com

Pythonユニットテストでtime.sleep()をスタブする方法

単体テストの実行時間を改善するために、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) 

ただし、上記の2番目のコード行(クラス定義)で次のエラーが発生します。

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

エラーを修正する方法は?

19
Michel Keijzers

テストでは 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
31
Mikko Ohtamaa

どうですか:

import time
from time import sleep as originalsleep

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

time.sleep = newsleep

これは私のために働いています。スピードを上げたいテストの最初にそれを含め、最後に念のため元のスリープを戻しました。それが役に立てば幸い

4
user3758302

私は 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 =
3
sashk

受け入れられた回答はまだ有効です。ただし、 nittest.mock は、Python 3.3 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)
1
Jeeppler

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デモ: 要点偽のスリープ関数フィクスチャ
0
linw1995