def __init__(self, target, *args, parent_context, **kwargs): super().__init__(target=target, **kwargs) self.exception_caught = None self.value_returned = None self.fake_datetime = FakeDatetime() self._context = parent_context.spawn() self._target = target
def setUp(self): self.context = open_dependency_context() self.fake_time = FakeDatetime() self.context.inject(datetime, self.fake_time) self.results = None EventBroker.subscribe(event=TestEvent.suite_results_compiled, func=self.capture_results) self.sut = ResultCompiler() self.sut.activate()
class ContextTimeController(Thread): """ Executes a function in a new thread that uses a fake datetime. This allows a test to manipulate time as perceived by the target function. """ """Initializer Behaves exactly like Thread.__init__ except that daemon defaults to True. target -- function to call in the thread parent_context -- inherit dependencies injected into this context """ def __init__(self, target, *args, parent_context, **kwargs): super().__init__(target=target, **kwargs) self.exception_caught = None self.value_returned = None self.fake_datetime = FakeDatetime() self._context = parent_context.spawn() self._target = target """Advance the fake clock by the given interval Raises a RuntimeError if the thread has not been started. Keyword arguments can be anything accepted by datetime.timedelta. """ def advance(self, **kwargs): if not self.ident: raise RuntimeError( "The thread must be started before advancing time") self.fake_datetime.advance(**kwargs) def run(self): self._context.inject(datetime, self.fake_datetime) self._context.attach_to_thread(self) try: self.value_returned = self._target() except Exception as e: self.exception_caught = e
def test_does_not_affect_origin_context(self): keep_running = True def forrest(): while keep_running: sleep(0.001) with dependency_context() as context: original_context_time = datetime.fromtimestamp(2) context_dt = FakeDatetime(fixed_time=original_context_time) context.inject(datetime, context_dt) tc = context.create_time_controller(target=forrest) tc.start() sleep(0.01) expect(dependency(datetime).now()).to(equal(original_context_time)) keep_running = False tc.join()
def test_sets_fixed_time_if_none_specified(self): expect(FakeDatetime().fixed_time).to(be_a(datetime))
def test_delegates_calls_to_datetime(self): expect(FakeDatetime().__call__).to(equal(datetime))
def test_can_advance_by_arbitrary_days(self): fake = FakeDatetime() days = 8 start = fake.now() fake.advance(days=days) expect(fake.now()).to(equal(start + timedelta(days=days)))
def test_can_advance_by_arbitrary_hours(self): fake = FakeDatetime() hours = 23 start = fake.now() fake.advance(hours=hours) expect(fake.now()).to(equal(start + timedelta(hours=hours)))
def test_can_advance_by_arbitrary_minutes(self): fake = FakeDatetime() mins = 4 start = fake.now() fake.advance(minutes=mins) expect(fake.now()).to(equal(start + timedelta(minutes=mins)))
def test_can_advance_by_arbitrary_sec(self): fake = FakeDatetime() sec = 235 start = fake.now() fake.advance(seconds=sec) expect(fake.now()).to(equal(start + timedelta(seconds=sec)))
def test_can_advance_by_arbitrary_ms(self): fake = FakeDatetime() ms = 235 start = fake.now() fake.advance(milliseconds=ms) expect(fake.now()).to(equal(start + timedelta(milliseconds=ms)))
def test_passes_other_dt_attributes_through(self): fake = FakeDatetime() for attr in dir(datetime): if not (attr.startswith("_") or attr in ("now", "utcnow")): assert getattr(fake, attr) == getattr( datetime, attr), f"{attr} did not pass through"
def test_utcnow_returns_fixed_time(self): now = datetime.now() expect(FakeDatetime(fixed_time=now).utcnow()).to(equal(now))
def test_can_specify_fixed_time(self): now = datetime.now() expect(FakeDatetime(fixed_time=now).fixed_time).to(equal(now))
def test_passes_other_dt_attributes_through(self): fake = FakeDatetime() for attr in dir(datetime): if not (attr.startswith('_') or attr in ('now', 'utcnow')): assert getattr(fake, attr) == getattr(datetime, attr), \ f'{attr} did not pass through'