Testing Persistence with Abstract Repositories


When it comes to testing your persistence implementations do you run into issues forming tests against databases while avoiding production code, but also dislike mocking to test your database calls? Try out an Abstract Repository!

import abc
class AbstractRepository(abc.ABC):
    @abc.abstractmethod
    def add(self, entity):
        raise NotImplementedError
        
    @abc.abstractmethod(self, id):
        raise NotImplementedError

Here’s an example of an Abstract Repository. At the most basic level we’ll want to add entities to our database and get entities from our database (by an id or other type of reference).

For example, your real Repository could look like the following:

class RealRepository(AbstractRepository):

    def __init__(self, database_session):
        self.database_session = database_session
        
    def add(self, entity):
        self.database_session.add(entity)
        
    def get(self, id):
        self.database_session.query().filter(id)

Now to safely test against your database, you can simply create a fake Repository which implements the Abstract Repository and ask it to use either a smaller (in-memory) database or a different data structure entirely. You can then use this fake Repository in your unit tests and avoid using mocks to test your database calls.

class MyFakeRepository(AbstractRepository):

    def __init__(self, list_of_entities: List):
        self.entities = list_of_entities
        
    def add(self, entity):
        self.entities.append(entity)
        
    def get(self, id):
        for entity in self.entities:
            if entity.id == id:
                return entity

Here’s a unit test example to see how this works:

from my_fake_repository import MyFakeRepository
class TestCase(unittest.TestCase):

    def test_database_get(self):
        entity_1 = Entity(id=1)
        entity_2 = Entity(id=2)
        entity_3 = Entity(id=3)
        entity_4 = Entity(id=4)
        fake_repository = MyFakeRepository([entity_1, entity_2, entity_3, entity_4])
        
        expected = 3
        result = fake_repository.get(expected)
        self.assertEqual(result.id, expected, msg="result.id {result.id} does not equal {expected}")

I hope you find this to be helpful! You can read more about the Repository Pattern in Architecture Patterns with Python, written by Harry Percival and Bob Gregory.

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *