fudge

Fudge is a module for replacing real objects with fakes (mocks, stubs, etc) while testing.

See Using Fudge for common scenarios.

fudge.clear_calls()

Begin a new set of calls on fake objects.

Specifically, clear out any calls that were made on previously registered fake objects and reset all call stacks. You should call this any time you begin making calls on fake objects.

This is also available as a decorator: fudge.with_fakes()

fudge.verify()

Verify that all methods have been called as expected.

Specifically, analyze all registered fake objects and raise an AssertionError if an expected call was never made to one or more objects.

This is also available as a decorator: fudge.with_fakes()

fudge.with_fakes(method)
Decorator that calls fudge.clear_calls() before method() and fudge.verify() afterwards.
class fudge.Fake(name=None, allows_any_call=False, callable=False, expect_call=False)

A fake object that replaces a real one while testing.

Most calls with a few exceptions return self so that you can chain them together to create readable code.

Keyword arguments:

name=None
Name of the class, module, or function you mean to replace. If not specified, Fake() will try to guess the name by inspecting the calling frame (if possible).
allows_any_call=False
When True, any method is allowed to be called on the Fake() instance. Each method will be a stub that does nothing if it has not been defined. Implies callable=True.
callable=False
When True, the Fake() acts like a callable. Use this if you are replacing a single method. See example below.
expect_call=True
When True, the Fake() acts like a callable that must be called (implies callable=True). Use this when replacing a single method that must be called. See example below.

Short example:

>>> import fudge
>>> auth = fudge.Fake('auth').expects('login').with_args('joe_username', 'joes_password')
>>> auth.login("joe_username", "joes_password") # now works
>>> fudge.clear_expectations()

When callable=True the object acts like a method

>>> import fudge
>>> login = fudge.Fake('login', callable=True)
>>> login() # can be called

When expect_call=True the object acts like a method that must be called

>>> import fudge
>>> login = fudge.Fake('login', expect_call=True).times_called(2)
>>> login()
>>> fudge.verify()
...
AssertionError: fake:login() was called 1 time(s). Expected 2.
>>> fudge.clear_expectations()

Instance methods will raise either AssertionError or fudge.FakeDeclarationError

calls(call)

Redefine a call.

The fake method will execute your function. I.E.:

>>> f = Fake().provides('hello').calls(lambda: 'Why, hello there')
>>> f.hello()
'Why, hello there'
expects(call_name)

Expect a call.

If the method call_name is never called, then raise an error. I.E.:

>>> session = Fake('session').expects('open').expects('close')
>>> import fudge
>>> fudge.clear_calls()
>>> session.open()
>>> fudge.verify()
...
AssertionError: fake:session.close() was not called

Note

If you want to also verify the order these calls are made in, use fudge.Fake.remember_order(). When using fudge.Fake.next_call() after expects(...), each new call will be part of the expected order

If you want to modify the next call for an expected method use fudge.Fake.next_call()

has_attr(**attributes)

Sets available attributes.

I.E.:

>>> User = Fake('User').provides('__init__').has_attr(name='Harry')
>>> user = User()
>>> user.name
'Harry'
next_call(for_method=None)

Start expecting or providing multiple calls.

Note

next_call() cannot be used in combination with 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()
...
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 fudge.Fake.remember_order() in combination with fudge.Fake.expects() and fudge.Fake.next_call() each new call will be part of the expected order.

provides(call_name)

Provide a call.

The call acts as a stub – no error is raised if it is not called.:

>>> session = Fake('session').provides('open').provides('close')
>>> import fudge
>>> fudge.clear_expectations() # from any previously declared fakes
>>> fudge.clear_calls()
>>> session.open()
>>> fudge.verify() # close() not called but no error

If you want to modify the next call for a provided method use fudge.Fake.next_call()

raises(exc)

Set last call to raise an exception class or instance.

For example:

>>> import fudge
>>> db = fudge.Fake('db').provides('insert').raises(ValueError("not enough parameters for insert"))
>>> db.insert()
...
ValueError: not enough parameters for insert
remember_order()

Verify that subsequent 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()
...
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 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()
returns(val)

Set the last call to return a value.

Set a static value to return when a method is called. I.E.:

>>> f = Fake().provides('get_number').returns(64)
>>> f.get_number()
64
returns_fake(*args, **kwargs)

Set the last call to return a new fudge.Fake.

Any given arguments are passed to the fudge.Fake constructor

Take note that this is different from the cascading nature of other methods. This will return an instance of the new Fake, not self, so you should be careful to store its return value in a new variable.

I.E.:

>>> session = Fake('session')
>>> query = session.provides('query').returns_fake(name="Query")
>>> assert query is not session
>>> query = query.provides('one').returns(['object'])

>>> session.query().one()
['object']
times_called(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()
...
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()
...
AssertionError: fake:auth.login() was called 1 time(s). Expected 2.

Note

This cannot be used in combination with fudge.Fake.next_call()

with_arg_count(count)

Set the last call to expect an exact argument count.

I.E.:

>>> auth = Fake('auth').provides('login').with_arg_count(2)
>>> auth.login('joe_user') # forgot password
...
AssertionError: fake:auth.login() was called with 1 arg(s) but expected 2
with_args(*args, **kwargs)

Set the last call to expect specific arguments.

>>> import fudge
>>> counter = fudge.Fake('counter').expects('increment').with_args(25, table='hits')
>>> counter.increment(24, table='clicks')
...
AssertionError: fake:counter.increment(25, table='hits') was called unexpectedly with args (24, table='clicks')

If you need to work with dynamic argument values consider using fudge.inspector functions. Here is an example of providing a more flexible with_args() declaration :

>>> import fudge
>>> from fudge.inspector import arg
>>> counter = fudge.Fake('counter')
>>> counter = counter.expects('increment').with_args(
...                                         arg.any_value(), 
...                                         table=arg.endswith("hits"))
... 

The above declaration would allow you to call counter like this:

>>> counter.increment(999, table="image_hits")
>>> fudge.verify()

Or like this:

>>> counter.increment(22, table="user_profile_hits")
>>> fudge.verify()
with_kwarg_count(count)

Set the last call to expect an exact count of keyword arguments.

I.E.:

>>> auth = Fake('auth').provides('login').with_kwarg_count(2)
>>> auth.login(username='joe') # forgot password=
...
AssertionError: fake:auth.login() was called with 1 keyword arg(s) but expected 2
class fudge.FakeDeclarationError
Exception in how this fudge.Fake was declared.

Previous topic

Why Another Mock Framework?

Next topic

fudge.inspector

This Page