def _get_current_call(self): if not self._last_declared_call_name: if not self._callable: raise FakeDeclarationError( "Call to a method that expects a predefined call but no such call exists. " "Maybe you forgot expects('method') or provides('method') ?") return self._callable.get_call_object() exp = self._declared_calls[self._last_declared_call_name].get_call_object() return exp
def times_called(self, n): """Set the number of times an object can be called. When working with provided calls, you'll only see an error if the expected call count is exceeded :: >>> auth = Fake('auth').provides('login').times_called(1) >>> auth.login() >>> auth.login() Traceback (most recent call last): ... AssertionError: fake:auth.login() was called 2 time(s). Expected 1. When working with expected calls, you'll see an error if the call count is never met :: >>> import fudge >>> auth = fudge.Fake('auth').expects('login').times_called(2) >>> auth.login() >>> fudge.verify() Traceback (most recent call last): ... AssertionError: fake:auth.login() was called 1 time(s). Expected 2. .. note:: This cannot be used in combination with :func:`fudge.Fake.next_call` """ if self._last_declared_call_name: actual_last_call = self._declared_calls[ self._last_declared_call_name] if isinstance(actual_last_call, CallStack): raise FakeDeclarationError( "Cannot use times_called() in combination with next_call()" ) # else: # self._callable is in effect exp = self._get_current_call() exp.expected_times_called = n return self
def remember_order(self): """Verify that subsequent :func:`fudge.Fake.expects` are called in the right order. For example:: >>> import fudge >>> db = fudge.Fake('db').remember_order().expects('insert').expects('update') >>> db.update() Traceback (most recent call last): ... AssertionError: Call #1 was fake:db.update(); Expected: #1 fake:db.insert(), #2 fake:db.update(), end >>> fudge.clear_expectations() When declaring multiple calls using :func:`fudge.Fake.next_call`, each subsequent call will be added to the expected order of calls :: >>> import fudge >>> sess = fudge.Fake("session").remember_order().expects("get_id").returns(1) >>> sess = sess.expects("set_id").with_args(5) >>> sess = sess.next_call(for_method="get_id").returns(5) Multiple calls to ``get_id()`` are now expected :: >>> sess.get_id() 1 >>> sess.set_id(5) >>> sess.get_id() 5 >>> fudge.verify() >>> fudge.clear_expectations() """ if self._callable: raise FakeDeclarationError( "remember_order() cannot be used for Fake(callable=True) or Fake(expect_call=True)" ) self._expected_call_order = ExpectedCallOrder(self) registry.remember_expected_call_order(self._expected_call_order) return self
def next_call(self, for_method=None): """Start expecting or providing multiple calls. .. note:: next_call() cannot be used in combination with :func:`fudge.Fake.times_called` Up until calling this method, calls are infinite. For example, before next_call() ... :: >>> from fudge import Fake >>> f = Fake().provides('status').returns('Awake!') >>> f.status() 'Awake!' >>> f.status() 'Awake!' After next_call() ... :: >>> from fudge import Fake >>> f = Fake().provides('status').returns('Awake!') >>> f = f.next_call().returns('Asleep') >>> f = f.next_call().returns('Dreaming') >>> f.status() 'Awake!' >>> f.status() 'Asleep' >>> f.status() 'Dreaming' >>> f.status() Traceback (most recent call last): ... AssertionError: This attribute of fake:unnamed can only be called 3 time(s). Call reset() if necessary or fudge.clear_calls(). If you need to affect the next call of something other than the last declared call, use ``next_call(for_method="other_call")``. Here is an example using getters and setters on a session object :: >>> from fudge import Fake >>> sess = Fake('session').provides('get_count').returns(1) >>> sess = sess.provides('set_count').with_args(5) Now go back and adjust return values for get_count() :: >>> sess = sess.next_call(for_method='get_count').returns(5) This allows these calls to be made :: >>> sess.get_count() 1 >>> sess.set_count(5) >>> sess.get_count() 5 When using :func:`fudge.Fake.remember_order` in combination with :func:`fudge.Fake.expects` and :func:`fudge.Fake.next_call` each new call will be part of the expected order. """ last_call_name = self._last_declared_call_name if for_method: if for_method not in self._declared_calls: raise FakeDeclarationError( "next_call(for_method=%r) is not possible; " "declare expects(%r) or provides(%r) first" % (for_method, for_method, for_method)) else: # set this for the local function: last_call_name = for_method # reset this for subsequent methods: self._last_declared_call_name = last_call_name if last_call_name: exp = self._declared_calls[last_call_name] elif self._callable: exp = self._callable else: raise FakeDeclarationError('next_call() must follow provides(), ' 'expects() or is_callable()') if getattr(exp, 'expected_times_called', None) is not None: raise FakeDeclarationError( "Cannot use next_call() in combination with times_called()") if not isinstance(exp, CallStack): # lazily create a stack with the last defined # expected call as the first on the stack: stack = CallStack(self, initial_calls=[exp], expected=isinstance(exp, ExpectedCall), call_name=exp.call_name) # replace the old call obj using the same name: if last_call_name: self._declare_call(last_call_name, stack) elif self._callable: self._callable = stack else: stack = exp # hmm, we need a copy here so that the last call # falls off the stack. if stack.expected: next_call = ExpectedCall(self, call_name=exp.call_name, call_order=self._expected_call_order) else: next_call = Call(self, call_name=exp.call_name) stack.add_call(next_call) return self