Exemplo n.º 1
0
 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
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
 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
Exemplo n.º 4
0
    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