Testing our data access layer with mocks

In previous chapters, we have written automated tests that involved stubbing out the data access layer. Now that we are in the heart of writing the data access layer, we need to look at ways to test our queries. To be specific, we need to make sure we are using DatabaseTemplate correctly, along with any custom row mapper we write.

Mocks are used to primarily record what functions are called, and provide options of returning certain values. The idea is to create a set of expected actions, and then call the actual API and measure if this is what happened. This is compared to stubs, which you code yourself and provide canned answers and don't necessarily care what methods were called. Both of these tools are useful for automated testing.

Note

Spring Python uses pmock, a Python library inspired by the fluent API of jMock (http://www.jmock.org/), to do some of its automated testing. You don't have to use this particular mocking library. There are lots of other candidates around. For our purposes we are going to use it here to show the general idea of mocking your data access layer for testing.

Due to lack of updates from the original developers of pmock, the source code of this library was added to Spring Python's set of managed code, and has some custom updates. See http://springpython.webfactional.com for details on downloading.

  1. First, let's code a simple DataAccess class that uses DatabaseTemplate to fetch the number of articles we have.
    class DataAccess(object):
    def __init__(self, conn_factory):
    self.dt = DatabaseTemplate(conn_factory)
    def count_wiki_articles(self):
    return self.dt.query_for_object("SELECT COUNT(*) FROM ARTICLE")
    

    This simple data access layer has one method: count_wiki_articles. It utilizes the code we wrote earlier involving the DatabaseTemplate. In this example, DataAccess expects to be initialized with a connection factory.

    Now, to test this out, we need DatabaseTemplate to do its job, but we want to catch it at the right point in order to inject some pre-built values. The piece of code that does the heavy lifting is Spring Python's cursor object, which is supplied by a connection. This means we need to code a special stubbed out connection factory that will hold a mocked cursor.

  2. Let's write a specialized class to act as a mocked connection.
    class MockedConnection(object):
    def __init__(self):
    self.mockCursor = None
    def cursor(self):
    return self.mockCursor
    

    This connection will supply DatabaseTemplate with a special type of mocked cursor. Further down, we will see how mockCursor gets populated.

  3. In order to use this, let's code a connection factory for DatabaseTemplate that produces this type of connection.
    class MockingDBFactory(ConnectionFactory):
    def __init__(self):
    ConnectionFactory.__init__(self, [types.TupleType])
    self.mockedConnection = MockedConnection()
    def connect(self):
    return self.mockedConnection
    

    When this connection factory is asked to connect to the database, it will return a MockedConnection.

  4. To tie this rigging together, we need to setup a MockTestCase. This is a special type of unit test that provides extra hooks to library calls of pmock.
    from pmock import *
    class DataAccessMockTestCase(MockTestCase):
    def setUp(self):
    # Create a mock instance to record events
    self.mock = self.mock()
    conn_factory = MockingDBFactory()
    conn_factory.mockedConnection.mockCursor = self.mock
    self.data_access = DataAccess(conn_factory)
    

    Here in the setUp method for our test, we grab an instance of mock(). This object has APIs to record expectations. The object is meant to be injected so that function calls are then made against it, and at the end of a MockTestCase test method, the results are compared with the expectations.

    In this situation, the mockCursor is the key holder of the mock. There is also a local copy, so that the MockTestCase has a handle to check out the results.

  5. After setting all this up, let's define a mocked test method.
    def testCountingArticles(self):
    self.mock.expects(once()).method("execute")
    self.mock.expects(once()).method("fetchall")
    .will(return_value([(2,)]))
    count = self.data_access.count_wiki_articles()
    self.assertEquals(count, 2)
    

    The first two steps of this test use the mock object to defi ne expectations. The mock is expected to receive an execute method call once, and also a fetchall method call. The fetchall will return a value of [(2,)].

    Not only do we get to check the assertions, but pmock will verify that each of these methods was invoked by DatabaseTemplate.

The first two steps of this test use the mock object to define expectations. The mock is expected to receive an execute method call once, and also a fetchall method call. The fetchall will return a value of [(2,)].

Not only do we get to check the assertions, but pmock will verify that each of these methods was invoked by DatabaseTemplate.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.17.139