def test_child_spy_caching( decoy: Decoy, call_handler: CallHandler, spy_creator: SpyCreator, ) -> None: """It should create a child spy only once.""" parent_spec = decoy.mock(cls=Spec) child_spec = decoy.mock(cls=Spec) child_spy = decoy.mock(cls=Spy) wrong_spy = decoy.mock(cls=Spy) decoy.when(parent_spec.get_child_spec("child")).then_return(child_spec) decoy.when(spy_creator.create(spec=child_spec, is_async=False)).then_return( child_spy, wrong_spy, ) subject = Spy( spec=parent_spec, call_handler=call_handler, spy_creator=spy_creator, ) assert subject.child is child_spy assert subject.child is child_spy
def test_decoy_creates_specless_spy(decoy: Decoy) -> None: """It should be able to create a spec-less spy.""" subject = decoy.mock() assert isinstance(subject, Spy) # test deprecated create_decoy_func method subject = decoy.create_decoy_func() assert isinstance(subject, Spy) # test naming the spy subject = decoy.mock(name="spy_name") assert repr(subject) == "<Decoy mock `spy_name`>"
async def test_async_context_manager_mock(decoy: Decoy) -> None: """It should be able to mock an async context manager.""" class _ValueReader(ContextManager[Any]): async def __aenter__(self) -> "_ValueReader": ... async def __aexit__(self, *args: Any) -> None: ... def get_value(self) -> int: ... value_reader = decoy.mock(cls=_ValueReader) def _handle_enter() -> _ValueReader: decoy.when(value_reader.get_value()).then_return(42) return value_reader def _handle_exit(*args: Any) -> None: decoy.when(value_reader.get_value()).then_raise( AssertionError("Context manager exited")) decoy.when(await value_reader.__aenter__()).then_do(_handle_enter) decoy.when(await value_reader.__aexit__(None, None, None)).then_do(_handle_exit) async with value_reader as subject: result = subject.get_value() assert result == 42 with pytest.raises(AssertionError, match="exited"): subject.get_value()
def test_property_getter_stub_then_raise(decoy: Decoy) -> None: """It should be able to stub a property getter to raise.""" subject = decoy.mock() decoy.when(subject.prop_name).then_raise(ValueError("oh no")) with pytest.raises(ValueError, match="oh no"): subject.prop_name
def test_property_getter_stub_then_return_multiple(decoy: Decoy) -> None: """It should be able to stub a property getter with multiple return values.""" subject = decoy.mock() decoy.when(subject.prop_name).then_return(43, 44) assert subject.prop_name == 43 assert subject.prop_name == 44 assert subject.prop_name == 44
def test_decoy_creates_specless_async_spy(decoy: Decoy) -> None: """It should be able to create an async specless spy.""" subject = decoy.mock(is_async=True) assert isinstance(subject, AsyncSpy) # test deprecated create_decoy_func method subject = decoy.create_decoy_func(is_async=True) assert isinstance(subject, AsyncSpy)
def test_when_then_raise(decoy: Decoy) -> None: """It should be able to configure a stub raise with a rehearsal.""" subject = decoy.mock(func=some_func) decoy.when(subject("goodbye")).then_raise(ValueError("oh no")) with pytest.raises(ValueError, match="oh no"): subject("goodbye")
def test_property_getter_stub_then_do(decoy: Decoy) -> None: """It should be able to stub a property getter to act.""" def _handle_get(*args: Any, **kwargs: Any) -> int: return 84 subject = decoy.mock() decoy.when(subject.prop_name).then_do(_handle_get) assert subject.prop_name == 84
def test_property_deleter_stub_then_rase(decoy: Decoy) -> None: """It should be able to stub a property deleter to raise.""" subject = decoy.mock() prop_rehearser = decoy.prop(subject.prop_name) decoy.when(prop_rehearser.delete()).then_raise(ValueError("oh no")) with pytest.raises(ValueError, match="oh no"): del subject.prop_name
def test_reset(decoy: Decoy) -> None: """It should be able to reset its state.""" subject = decoy.mock(cls=SomeClass) subject.foo("hello") decoy.reset() with pytest.raises(AssertionError): decoy.verify(subject.foo("hello"))
def test_property_getter_stub_reconfigure(decoy: Decoy) -> None: """It should be able to reconfigure a property getter.""" subject = decoy.mock() decoy.when(subject.prop_name).then_return(42) assert subject.prop_name == 42 decoy.when(subject.prop_name).then_return(43) assert subject.prop_name == 43
def test_decoy_creates_func_spy(decoy: Decoy) -> None: """It should be able to create a Spy from a function.""" subject = decoy.mock(func=some_func) assert isinstance(subject, Spy) # test deprecated create_decoy_func method subject = decoy.create_decoy_func(spec=some_func) assert isinstance(subject, Spy)
async def test_verify_async(decoy: Decoy) -> None: """It should be able to configure a verification with an async rehearsal.""" subject = decoy.mock(cls=SomeAsyncClass) await subject.foo("hello") decoy.verify(await subject.foo("hello")) with pytest.raises(AssertionError): decoy.verify(await subject.foo("goodbye"))
def test_create_async_spy(decoy: Decoy, call_handler: CallHandler) -> None: """It should get default configurations from the spec.""" spec = decoy.mock(cls=Spec) decoy.when(spec.get_is_async()).then_return(True) subject = SpyCreator(call_handler=call_handler) result = subject.create(spec=spec) assert isinstance(result, AsyncSpy)
def test_verify(decoy: Decoy) -> None: """It should be able to configure a verification with a rehearsal.""" subject = decoy.mock(func=some_func) subject("hello") decoy.verify(subject("hello")) decoy.verify(subject(val="hello")) with pytest.raises(errors.VerifyError): decoy.verify(subject("goodbye"))
async def test_when_async(decoy: Decoy) -> None: """It should be able to stub an async method.""" subject = decoy.mock(cls=SomeAsyncClass) decoy.when(await subject.foo("hello")).then_return("world") decoy.when(await subject.bar(0, 1.0, "2")).then_raise(ValueError("oh no")) assert await subject.foo("hello") == "world" with pytest.raises(ValueError, match="oh no"): await subject.bar(0, 1.0, "2")
def test_when_ignore_extra_args(decoy: Decoy) -> None: """It should be able to ignore extra args in a stub rehearsal.""" def _get_a_thing(id: str, default: Optional[int] = None) -> int: raise NotImplementedError("intentionally unimplemented") subject = decoy.mock(func=_get_a_thing) decoy.when(subject("some-id"), ignore_extra_args=True).then_return(42) result = subject("some-id", 101) assert result == 42
def test_decoy_creates_spy(decoy: Decoy) -> None: """It should be able to create a Spy from a class.""" subject = decoy.mock(cls=SomeClass) assert isinstance(subject, SomeClass) assert isinstance(subject, Spy) # test deprecated create_decoy method subject = decoy.create_decoy(spec=SomeClass) assert isinstance(subject, SomeClass) assert isinstance(subject, Spy)
class DecoyTestCase(unittest.TestCase): """Decoy test case using unittest.""" def setUp(self) -> None: """Set up before each test.""" self.decoy = Decoy() def tearDown(self) -> None: """Clean up after each test.""" self.decoy.reset() def test_when(self) -> None: """Test that self.decoy.when works.""" mock = self.decoy.mock(cls=SomeClass) self.decoy.when(mock.foo("hello")).then_return("world") assert mock.foo("hello") == "world" def test_verify(self) -> None: """Test that self.decoy.verify works.""" mock = self.decoy.mock(cls=SomeClass) mock.foo("hello") self.decoy.verify(mock.foo("hello"))
def test_verify_call_list(decoy: Decoy) -> None: """It should be able to verify multiple calls.""" subject_1 = decoy.mock(cls=SomeClass) subject_2 = decoy.mock(cls=SomeNestedClass) subject_1.foo("hello") subject_2.child.bar(1, 2.0, "3") subject_1.foo("goodbye") decoy.verify( subject_1.foo("hello"), subject_2.child.bar(1, 2.0, "3"), subject_1.foo("goodbye"), ) with pytest.raises(errors.VerifyError): decoy.verify( subject_1.foo("hello"), subject_1.foo("goodbye"), subject_2.child.bar(1, 2.0, "3"), )
def test_property_setter_stub_then_raise(decoy: Decoy) -> None: """It should be able to stub a property setter to raise.""" subject = decoy.mock() prop_rehearser = decoy.prop(subject.prop_name) decoy.when(prop_rehearser.set(42)).then_raise(ValueError("oh no")) subject.prop_name = 41 assert subject.prop_name == 41 with pytest.raises(ValueError, match="oh no"): subject.prop_name = 42
def test_child_spy( decoy: Decoy, call_handler: CallHandler, spy_creator: SpyCreator, ) -> None: """It should create a child spy.""" parent_spec = decoy.mock(cls=Spec) child_spec = decoy.mock(cls=Spec) child_spy = decoy.mock(cls=Spy) decoy.when(parent_spec.get_child_spec("child")).then_return(child_spec) decoy.when(spy_creator.create(spec=child_spec, is_async=False)).then_return(child_spy) subject = Spy( spec=parent_spec, call_handler=call_handler, spy_creator=spy_creator, ) result = subject.child assert result is child_spy
def test_generator_context_manager_mock(decoy: Decoy) -> None: """It should be able to mock a generator-based context manager.""" class _ValueReader: def get_value(self) -> int: ... class _ValueReaderLoader: @contextlib.contextmanager def get_value_reader(self) -> Iterator[_ValueReader]: ... value_reader_loader = decoy.mock(cls=_ValueReaderLoader) value_reader = decoy.mock(cls=_ValueReader) decoy.when( value_reader_loader.get_value_reader()).then_enter_with(value_reader) decoy.when(value_reader.get_value()).then_return(42) with value_reader_loader.get_value_reader() as subject: result = subject.get_value() assert result == 42
def test_verify_times(decoy: Decoy) -> None: """It should be able to verify a call count.""" subject = decoy.mock(func=some_func) subject("hello") decoy.verify(subject("hello"), times=1) decoy.verify(subject("goodbye"), times=0) with pytest.raises(errors.VerifyError): decoy.verify(subject("hello"), times=0) with pytest.raises(errors.VerifyError): decoy.verify(subject("hello"), times=2)
def test_when_then_return(decoy: Decoy) -> None: """It should be able to configure a stub return with a rehearsal.""" subject = decoy.mock(func=some_func) decoy.when(subject("hello")).then_return("hello world") result = subject(val="hello") assert result == "hello world" result = subject(val="hello") assert result == "hello world" result = subject("asdfghjkl") assert result is None
async def test_async_generator_context_manager_mock(decoy: Decoy) -> None: """It should be able to mock a generator-based context manager.""" class _ValueReader: def get_value(self) -> int: ... class _ValueReaderLoader: @contextlib.asynccontextmanager async def get_value_reader(self) -> AsyncIterator[_ValueReader]: raise NotImplementedError() yield value_reader_loader = decoy.mock(cls=_ValueReaderLoader) value_reader = decoy.mock(cls=_ValueReader) decoy.when( value_reader_loader.get_value_reader()).then_enter_with(value_reader) decoy.when(value_reader.get_value()).then_return(42) async with value_reader_loader.get_value_reader() as subject: result = subject.get_value() assert result == 42
async def test_spy_async_context_manager( decoy: Decoy, call_handler: CallHandler, spy_creator: SpyCreator, spec: Spec, ) -> None: """It should be usable in an `async with` statement.""" enter_spec = decoy.mock(cls=Spec) exit_spec = decoy.mock(cls=Spec) enter_spy = decoy.mock(cls=AsyncSpy) exit_spy = decoy.mock(cls=AsyncSpy) error = RuntimeError("oh no") decoy.when(spec.get_name()).then_return("spy_name") decoy.when(spec.get_child_spec("__aenter__")).then_return(enter_spec) decoy.when(spec.get_child_spec("__aexit__")).then_return(exit_spec) decoy.when(spy_creator.create(spec=enter_spec, is_async=True)).then_return(enter_spy) decoy.when(spy_creator.create(spec=exit_spec, is_async=True)).then_return(exit_spy) decoy.when(await enter_spy()).then_return(42) subject = Spy(spec=spec, call_handler=call_handler, spy_creator=spy_creator) tb = None try: async with subject as result: assert result == 42 raise error except RuntimeError: tb = sys.exc_info()[2] pass decoy.verify(await exit_spy(RuntimeError, error, tb))
def test_mock_with_name( decoy: Decoy, spy_creator: SpyCreator, call_handler: CallHandler, subject: DecoyCore, ) -> None: """It should create a generic spy by default.""" spy = decoy.mock(cls=Spy) decoy.when(spy_creator.create(spec=None, name="my-spy", is_async=False)).then_return(spy) result = subject.mock(name="my-spy") assert result is spy
def test_when_then_do(decoy: Decoy) -> None: """It should be able to configure a stub action with a rehearsal.""" subject = decoy.mock(func=some_func) action_result = None def _then_do_action(arg: str) -> str: nonlocal action_result action_result = arg return "hello from the other side" decoy.when(subject("what's up")).then_do(_then_do_action) result = subject("what's up") assert action_result == "what's up" assert result == "hello from the other side"
def test_create_spy(decoy: Decoy, call_handler: CallHandler) -> None: """It should get default configurations from the spec.""" spec = decoy.mock(cls=Spec) sig = inspect.signature(some_func) decoy.when(spec.get_full_name()).then_return("hello.world") decoy.when(spec.get_signature()).then_return(sig) decoy.when(spec.get_class_type()).then_return(SomeClass) subject = SpyCreator(call_handler=call_handler) result = subject.create(spec=spec, name="foo") assert isinstance(result, Spy) assert isinstance(result, SomeClass) assert inspect.signature(result) == sig assert repr(result) == "<Decoy mock `hello.world`>"