skip to navigation
skip to content

Not Logged In

pymockobject 0.5

Mock Object library

pymockobject - A Mock object library for Python.
==================================

Introduction
----------
pymockobject is mockobject library, designed to be used by unit tests written
in Python.

Mock objects are typically employed in a unittest when a dependacy of the class
under test needs to access an external, or expensive-to-access resource.
Another usage case is to reduce the number of dependancies in tests.
In both of these scenarios, when the interface of the object class that the
mock object replaces in test changes, it is desirable that we don't have to
go around changing the mock object definitions we created in the tests.

Motivation
---------

A few mock object frameworks are availbale for python, so why create another?

 - Mock objects should not be created unless they match the type they are
    mocking in terms of method signatures.

    That is, if the object you are mocking 'Foo', has a method 'bar' defined as:
       def bar(self, a, b, c=None):
           .....
     Then a call to such as :
          mock.bar(1,2,3, d=4)

     should fail, since the real 'bar' method does not take a keyword parameter 'd'.

- Mock objects should be a subclass of the target subject
   -  This permits code which uses type-checking via isinstance, cmp, eq and friends
        to work with mock objects.

- A mock object's method should respond to messages, rather than passing a message
   to the mock object along with a string identifying the method (usually by name).
   I considered:
           mock.foo()
           mock.assert_called("foo", *with_args, **with_kwargs)
                                             vs.
           mock.foo()
           mock.foo.assert_called(*with_args, **with_kwargs)

    and concluded I prefer the later (which is the current implementation).
    Whilst this could be seen as a style preferance,  I believe accessing the method
    as an attribute to be (arguably) more readable, but more importantly more
    transparent as to what's going on.  It is the method's state which we are interested
    in most cases;  The only requests that we ask commonly of the mock object itself
    is to enumerate an ordered list of all the calls that have been made on it, or
    to ask for all calls made on it of a give name.

Aims
----

- Produce more concise unit test code, by having less user defined mock objects
   in scope.
   -  Hopefully, as a side effect of this, more readable tests.

- Reduce the amount of maintainance require to maintain tests as class interfaces
   change.  By insisting on creating a mock with the target type, there should be no
   need to update the tests each time a developer decides to rename a method.
   - This should hopefully reduce the lifecycle time of writing tests as consequence.

- Allow the use of mock objects in tests where it has before not possible due to type
   checking (via isinstance or otherwise).

Features
-------

 - Ensures that the methods mocked match the signatures of the subject.
    i.e it is not possible to create a mock method 'foo' of object  'spam'
        if 'foo' is not a named member of spam.__class__

 - Ability  to inspect the state of mock calls

 - Installed as a python package

 - Ability to specifiy pre and post call expectations for mock methods

- Supports installation as python eggs.
   See INSTALL for details.

- Comprehensive documentation and tests provided,
   For the main doctests, look at: pymockobject/__init__.py
   All unittests for pymockobject live in the 'tests' sub-package.

Outstanding design questions
------------------------

 - Should "Anonymous" mock object's be supported?
    - An anonymous mock is a mock object that does not claim to be of any
       specific type, instead it responds to any message (known as a "Tracer Buillet"),
       A tracer buillet can be used in a program, and later inspected to find out which
       methods have been called, how the program attempted to alter its state.
       In my opinion, this is not a mock object, but a variation of a tracer butllet[1].
       Mock objects, should as their name inferrs, simulate the type of the object
       that will be passed to the code under test under production circumstances.
       Where polymorphism applies, and the object may vary according to an interface or
       base class, i propose that the unittest should employ a test that creates a mock
       object for each of the variations, where applicable.

       Should anyone have any compelling reasons why the above doesn't hold true,
       please let me know of any use cases and I'll try to address them.
       My assertions about anonymous mocks are purely driven from practical
       experience.

 - Should 'partial' mock objects be supported?
    - A partial mock is a mock object that by default delgates to the instance of the
       the type mocked - i.e calls the real code by default.
       The idea is that one can mock out parts of the object under test, but allow the
       the rest of the object to function as if it were the real thing.
       Initially I thought this would be a cool feature to have, but after some thought, and
       reading (www.mockobjects.com and others), I decided that I agreed with thathe
       assertions others have made, if you find yourself wanting to mock out part of an
       object, then that object is usually too large and can be decomposed into smaller
       well defined compontents.

Todo
----

- Support any Python method type [?]

   Ideally, any method type, including slot wrappers, builtin-methods
   should be supported, unfortunatly, when mocking builtin types (dict, list, et al)
   it is not currently possible (in Python 2.4.3) to inspect the argument
   specification of methods, which are
   defined of these types (they are of the types "method_descriptor", "slot_wrapper",
   "builtin_function_or_method".  This is because these methods are defined in C,
   and the current Python C API does not expose a mechanism to retrieve method
   arguments.  This also means that descriptor methods such as
   __str__, __repr__, __eq___ et al cannot be mocked (these are of the type
   'method_descriptor', and these cannot be mocked, however, this will not cause
   pymockobject to fail, instead it detects these method types and ignores them.

   Mocking builtin objects is still supported, since it can be still useful for
   other mock object features (expectations, call inspection).

   The details of how the current implementation decides whether an instance's method
   can be mocked can by found by reading the function:
       pymockobject.reflect.get_methods

Known Bugs
----------


--------------------------------------------
If you find some or all of this module useful, please
donate a small amount to the Free Software Foundation,
Thanks!
File Type Py Version Size # downloads
pymockobject-0.5-py2.4.egg (md5) Python Egg 2.4 86KB 290
pymockobject-0.5.tar.gz (md5) Source 24KB 166