単体テストの実行時間を改善するために、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).
エラーを修正する方法は?
テストでは 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
どうですか:
import time
from time import sleep as originalsleep
def newsleep(seconds):
sleep_speed_factor = 10.0
originalsleep(seconds/sleep_speed_factor)
time.sleep = newsleep
これは私のために働いています。スピードを上げたいテストの最初にそれを含め、最後に念のため元のスリープを戻しました。それが役に立てば幸い
私は 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 =
受け入れられた回答はまだ有効です。ただし、 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)
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)
- 一般的なデモ: freezegun README を参照してください
- pytestデモ: 要点偽のスリープ関数フィクスチャ