diff --git a/README.rst b/README.rst index e510f64..918043e 100644 --- a/README.rst +++ b/README.rst @@ -119,6 +119,7 @@ Stub *New in version 0.6* The stub is a mock object that accepts any arguments and is useful to test callbacks, for instance. +May be passed a name to be used by the constructed stub object in its repr (useful for debugging). .. code-block:: python @@ -126,7 +127,7 @@ The stub is a mock object that accepts any arguments and is useful to test callb def foo(on_something): on_something('foo', 'bar') - stub = mocker.stub() + stub = mocker.stub(name='on_something_stub') foo(stub) stub.assert_called_once_with('foo', 'bar') diff --git a/pytest_mock.py b/pytest_mock.py index 63e2a82..ecbae66 100644 --- a/pytest_mock.py +++ b/pytest_mock.py @@ -70,15 +70,16 @@ def spy(self, obj, name): autospec=autospec) return result - def stub(self): + def stub(self, name=None): """ Creates a stub method. It accepts any arguments. Ideal to register to callbacks in tests. + :param name: the constructed stub's name as used in repr :rtype: mock.MagicMock :return: Stub object. """ - return mock_module.MagicMock(spec=lambda *args, **kwargs: None) + return mock_module.MagicMock(spec=lambda *args, **kwargs: None, name=name) class _Patcher(object): """ diff --git a/test_pytest_mock.py b/test_pytest_mock.py index 703d165..4e3a535 100644 --- a/test_pytest_mock.py +++ b/test_pytest_mock.py @@ -168,14 +168,35 @@ def test_mocker_resetall(mocker): assert not open.called -def test_mocker_stub(mocker): - def foo(on_something): - on_something('foo', 'bar') - - stub = mocker.stub() - - foo(stub) - stub.assert_called_once_with('foo', 'bar') +class TestMockerStub: + def test_call(self, mocker): + stub = mocker.stub() + stub('foo', 'bar') + stub.assert_called_once_with('foo', 'bar') + + def test_repr_with_no_name(self, mocker): + stub = mocker.stub() + assert not 'name' in repr(stub) + + def test_repr_with_name(self, mocker): + test_name = 'funny walk' + stub = mocker.stub(name=test_name) + assert "name={!r}".format(test_name) in repr(stub) + + def __test_failure_message(self, mocker, **kwargs): + expected_name = kwargs.get('name') or 'mock' + expected_message = 'Expected call: {}()\nNot called'.format(expected_name) + stub = mocker.stub(**kwargs) + with pytest.raises(AssertionError) as exc_info: + stub.assert_called_with() + assert exc_info.value.msg == expected_message + + def test_failure_message_with_no_name(self, mocker): + self.__test_failure_message(mocker) + + @pytest.mark.parametrize('name', (None, '', 'f', 'The Castle of aaarrrrggh')) + def test_failure_message_with_name(self, mocker, name): + self.__test_failure_message(mocker, name=name) def test_instance_method_spy(mocker):