Skip to content

Commit

Permalink
Merge pull request #93 from kaste/fix-69
Browse files Browse the repository at this point in the history
  • Loading branch information
kaste authored Jan 24, 2025
2 parents 958b1d8 + 939cd48 commit 2722af6
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 15 deletions.
3 changes: 3 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Release 1.5.5
--------------------------------

- Improved behavior of the ad-hoc methods of mocks. (#92)
- Make the shortcut `when(mock).foo().thenReturn()` officially work and just assume
the user forgot the `None` as return value.
- Disallow the shortcut `when(mock).foo().thenAnswer()` as it reads odd.



Expand Down
14 changes: 8 additions & 6 deletions mockito/invocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,13 +405,13 @@ def check_used(self):
"\nUnused stub: %s" % self)


def return_(value, *a, **kw):
def answer(*a, **kw):
def return_(value):
def answer(*args, **kwargs):
return value
return answer

def raise_(exception, *a, **kw):
def answer(*a, **kw):
def raise_(exception):
def answer(*args, **kwargs):
raise exception
return answer

Expand All @@ -431,18 +431,20 @@ def __init__(self, invocation):
invocation.mock.eat_self(invocation.method_name)

def thenReturn(self, *return_values):
for return_value in return_values:
for return_value in return_values or (None,):
answer = return_(return_value)
self.__then(answer)
return self

def thenRaise(self, *exceptions):
for exception in exceptions:
for exception in exceptions or (Exception,):
answer = raise_(exception)
self.__then(answer)
return self

def thenAnswer(self, *callables):
if not callables:
raise TypeError("No answer function provided")
for callable in callables:
answer = callable
if self.discard_first_arg:
Expand Down
7 changes: 5 additions & 2 deletions mockito/mockito.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,12 @@ def when(obj, strict=True):
expected call counts up front.
If your function is pure side effect and does not return something, you
can omit the specific answer. The default then is `None`::
can omit the specific answer. The function will then return `None` as by
default for Python functions::
when(manager).do_work()
when(manager).do_work().thenReturn()
# However, using `expect` may read better.
expect(manager).do_work()
`when` verifies the method name, the expected argument signature, and the
actual, factual arguments your code under test uses against the original
Expand Down
44 changes: 37 additions & 7 deletions tests/when_interface_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __hash__(self):


@pytest.mark.usefixtures('unstub')
class TestUserExposedInterfaces:
class TestEnsureEmptyInterfacesAreReturned:

def testWhen(self):
whening = when(Dog)
Expand All @@ -35,9 +35,30 @@ def testVerify(self):
assert verifying.__dict__ == {}


def testEnsureUnhashableObjectCanBeMocked(self):
obj = Unhashable()
when(obj).update().thenReturn(None)
def testEnsureUnhashableObjectCanBeMocked():
obj = Unhashable()
when(obj).update().thenReturn(None)


class TestAnswerShortcuts:
def testAssumeReturnNoneIfOmitted(self):
dog = Dog()
when(dog).bark().thenReturn().thenReturn(42)
assert dog.bark() is None
assert dog.bark() == 42

def testRaiseIfAnswerIsOmitted(self):
dog = Dog()
with pytest.raises(TypeError) as exc:
when(dog).bark().thenAnswer()
assert str(exc.value) == "No answer function provided"

def testAssumeRaiseExceptionIfOmitted(self):
dog = Dog()
when(dog).bark().thenRaise().thenReturn(42)
with pytest.raises(Exception):
dog.bark()
assert dog.bark() == 42


@pytest.mark.usefixtures('unstub')
Expand Down Expand Up @@ -92,13 +113,22 @@ def testReconfigureLooseMock(self):
verify(Dog).waggle()
verify(Dog).weggle()

# Where to put this test?
def testEnsureAddedAttributesGetRemovedOnUnstub(self):

class TestEnsureAddedAttributesGetRemovedOnUnstub:
def testWhenPatchingTheClass(self):
with when(Dog, strict=False).wggle():
pass

with pytest.raises(AttributeError):
getattr(Dog, 'wggle')
Dog.wggle

def testWhenPatchingAnInstance(self):
dog = Dog()
with when(dog, strict=False).wggle():
pass

with pytest.raises(AttributeError):
dog.wggle


@pytest.mark.usefixtures('unstub')
Expand Down

0 comments on commit 2722af6

Please sign in to comment.