让你的Python测试穿越时光
项目描述
FreezeGun是一个库,允许您的Python测试通过模拟datetime模块穿越时光。
用法
一旦调用装饰器或上下文管理器,对datetime.datetime.now()、datetime.datetime.utcnow()、datetime.date.today()、time.time()、time.localtime()、time.gmtime()和time.strftime()的所有调用都将返回已冻结的时间。time.monotonic()和time.perf_counter()也将被冻结,但通常它不对它们的绝对值做出保证,只对它们随时间的变化做出保证。
装饰器
from freezegun import freeze_time
import datetime
import unittest
# Freeze time for a pytest style test:
@freeze_time("2012-01-14")
def test():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
# Or a unittest TestCase - freezes for every test, and set up and tear down code
@freeze_time("1955-11-12")
class MyTests(unittest.TestCase):
def test_the_class(self):
assert datetime.datetime.now() == datetime.datetime(1955, 11, 12)
# Or any other class - freezes around each callable (may not work in every case)
@freeze_time("2012-01-14")
class Tester(object):
def test_the_class(self):
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
# Or method decorator, might also pass frozen time object as kwarg
class TestUnitTestMethodDecorator(unittest.TestCase):
@freeze_time('2013-04-09')
def test_method_decorator_works_on_unittest(self):
self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today())
@freeze_time('2013-04-09', as_kwarg='frozen_time')
def test_method_decorator_works_on_unittest(self, frozen_time):
self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today())
self.assertEqual(datetime.date(2013, 4, 9), frozen_time.time_to_freeze.today())
@freeze_time('2013-04-09', as_kwarg='hello')
def test_method_decorator_works_on_unittest(self, **kwargs):
self.assertEqual(datetime.date(2013, 4, 9), datetime.date.today())
self.assertEqual(datetime.date(2013, 4, 9), kwargs.get('hello').time_to_freeze.today())
上下文管理器
from freezegun import freeze_time
def test():
assert datetime.datetime.now() != datetime.datetime(2012, 1, 14)
with freeze_time("2012-01-14"):
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
assert datetime.datetime.now() != datetime.datetime(2012, 1, 14)
原始使用
from freezegun import freeze_time
freezer = freeze_time("2012-01-14 12:00:01")
freezer.start()
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14, 12, 0, 1)
freezer.stop()
时区
from freezegun import freeze_time
@freeze_time("2012-01-14 03:21:34", tz_offset=-4)
def test():
assert datetime.datetime.utcnow() == datetime.datetime(2012, 1, 14, 3, 21, 34)
assert datetime.datetime.now() == datetime.datetime(2012, 1, 13, 23, 21, 34)
# datetime.date.today() uses local time
assert datetime.date.today() == datetime.date(2012, 1, 13)
@freeze_time("2012-01-14 03:21:34", tz_offset=-datetime.timedelta(hours=3, minutes=30))
def test_timedelta_offset():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 13, 23, 51, 34)
良好的输入
FreezeGun在幕后使用dateutil,因此您可以使用看起来不错的datetimes。
@freeze_time("Jan 14th, 2012")
def test_nice_datetime():
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
函数和生成器对象
FreezeGun能够处理函数和生成器对象。
def test_lambda():
with freeze_time(lambda: datetime.datetime(2012, 1, 14)):
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
def test_generator():
datetimes = (datetime.datetime(year, 1, 1) for year in range(2010, 2012))
with freeze_time(datetimes):
assert datetime.datetime.now() == datetime.datetime(2010, 1, 1)
with freeze_time(datetimes):
assert datetime.datetime.now() == datetime.datetime(2011, 1, 1)
# The next call to freeze_time(datetimes) would raise a StopIteration exception.
tick 参数
FreezeGun 有一个额外的 tick 参数,可以将时间重置到指定值,但时间会继续流逝。这是对默认参数的替代,默认参数会使时间停止。
@freeze_time("Jan 14th, 2020", tick=True)
def test_nice_datetime():
assert datetime.datetime.now() > datetime.datetime(2020, 1, 14)
auto_tick_seconds 参数
FreezeGun 有一个额外的 auto_tick_seconds 参数,每次从起始值自动递增指定数量的值。这是对默认参数的替代,默认参数会使时间停止。注意,给定 auto_tick_seconds 后,tick 参数将被忽略。
@freeze_time("Jan 14th, 2020", auto_tick_seconds=15)
def test_nice_datetime():
first_time = datetime.datetime.now()
auto_incremented_time = datetime.datetime.now()
assert first_time + datetime.timedelta(seconds=15) == auto_incremented_time
手动计时
FreezeGun 允许手动向前推进时间。
def test_manual_tick():
initial_datetime = datetime.datetime(year=1, month=7, day=12,
hour=15, minute=6, second=3)
with freeze_time(initial_datetime) as frozen_datetime:
assert frozen_datetime() == initial_datetime
frozen_datetime.tick()
initial_datetime += datetime.timedelta(seconds=1)
assert frozen_datetime() == initial_datetime
frozen_datetime.tick(delta=datetime.timedelta(seconds=10))
initial_datetime += datetime.timedelta(seconds=10)
assert frozen_datetime() == initial_datetime
def test_monotonic_manual_tick():
initial_datetime = datetime.datetime(year=1, month=7, day=12,
hour=15, minute=6, second=3)
with freeze_time(initial_datetime) as frozen_datetime:
monotonic_t0 = time.monotonic()
frozen_datetime.tick(1.0)
monotonic_t1 = time.monotonic()
assert monotonic_t1 == monotonic_t0 + 1.0
将时间移动到指定日期时间
FreezeGun 允许将时间移动到特定日期。
def test_move_to():
initial_datetime = datetime.datetime(year=1, month=7, day=12,
hour=15, minute=6, second=3)
other_datetime = datetime.datetime(year=2, month=8, day=13,
hour=14, minute=5, second=0)
with freeze_time(initial_datetime) as frozen_datetime:
assert frozen_datetime() == initial_datetime
frozen_datetime.move_to(other_datetime)
assert frozen_datetime() == other_datetime
frozen_datetime.move_to(initial_datetime)
assert frozen_datetime() == initial_datetime
@freeze_time("2012-01-14", as_arg=True)
def test(frozen_time):
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
frozen_time.move_to("2014-02-12")
assert datetime.datetime.now() == datetime.datetime(2014, 2, 12)
move_to 参数可以是任何有效的 freeze_time 日期(字符串、日期、datetime)。
默认参数
请注意,FreezeGun 不会修改默认参数。以下代码将打印当前日期。请参阅此处了解原因。
from freezegun import freeze_time
import datetime as dt
def test(default=dt.date.today()):
print(default)
with freeze_time('2000-1-1'):
test()
安装
要安装 FreezeGun,只需
$ pip install freezegun
在 Debian 系统上
$ sudo apt-get install python-freezegun
忽略包
有时需要忽略特定包(例如库)的 FreezeGun 行为。可以通过单个调用忽略它们
from freezegun import freeze_time
with freeze_time('2020-10-06', ignore=['threading']):
# ...
默认情况下,FreezeGun 忽略以下包
[
'nose.plugins',
'six.moves',
'django.utils.six.moves',
'google.gax',
'threading',
'Queue',
'selenium',
'_pytest.terminal.',
'_pytest.runner.',
'gi',
]
可以设置自己的默认忽略列表
import freezegun
freezegun.configure(default_ignore_list=['threading', 'tensorflow'])
请注意,这将覆盖默认忽略列表。如果想要扩展现有默认值,请使用
import freezegun
freezegun.configure(extend_ignore_list=['tensorflow'])
项目详情
下载文件
下载您平台的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。