pythonmongodbpytestmongoenginemongomock

How to realize tests on functions which are using mongoengine connection in Python?


I have Fast API with a Mongo Database I try to realize my tests for some functions which need mongo connection Here my collection users and its fields:

from mongoengine import Document, EmailField, StringField, EnumField 
class User(Document):  
    meta = {"collection": "users"}
    email = EmailField(unique=True)
    hashed_password = StringField()
    role = EnumField(UserRole)

    def username(self):
        return self.email.split('@')[0]

    def __str__(self):
        return f'{self.email} ({self.role})

Here my function

class UserService:

    @staticmethod
    def existing_user(email: str) -> Optional[User]:


        try:
             user = User.objects(email=email).first()
        except ServerSelectionTimeoutError as e:
            raise e

        return user

What is the best way to test this function please (using pytest)? I would like to mock my MongoDB but I didn't manage with mongomock or directly with monkeypatch

Thank you very much

My test file

 from domain.entities.user import UserRole, User
 from mongomock import MongoClient
 class TestUserServiceMethods:

    email="john@doe.fr"

    # User example
    user = User(email=email,
                  role=UserRole.admin,
                  hashed_password="hashed_pwd")

    add_user = {
      "email": email,
      "role": UserRole.admin,
      "hashed_password": "hashed_pwd"
    }

    

    user_service = UserService()

    client = MongoClient()

    mock_db = client['ml-db']
    user_collection = mock_db['users']
    user_collection.insert_one(add_user)



    def test_existing_user(self, monkeypatch):
        with monkeypatch.context() as m:
            m.setattr('pymongo.MongoClient', lambda *args, **kwargs: self.client)

            result = self.user_service.existing_user(self.email)

             assert result == self.user

It seems the mock didn't sucess because I got as error :

mongoengine.connection.ConnectionFailure: You have not defined a default connection

Should I use directly Fast app with test_client?


Solution

  • UPDATE As Ozs said, the best way is to create a Fake database and to drop it at the end. Here an example which resolves my problem

    from unittest import TestCase
    
    from mongoengine import connect
    
    import UserService, password_context 
    import UserRole, User
    
    
    class TestUserServiceMethods(TestCase):
    
        @classmethod
        def setUpClass(cls):
            cls.connection = connect('mongoenginetest', host='mongomock://localhost/ml-db')
    
        def setUp(cls):
            cls.data = {
                "id": "6499594c58ebb74dd4985e59",
                "email": "mail@test.fr",
                "pwd": "test",
                "hashed_pwd": password_context.hash("test"),
                "role": UserRole.admin
            }
    
            cls.doc = {
                "email": cls.data['email'],
                "role": cls.data['role'],
                "hashed_password": cls.data['hashed_pwd']
            }
          
    
            cls.user = User(
                email=cls.data['email'],
                role=cls.data['role'],
                hashed_password=cls.data['hashed_pwd'])
    
            cls.user_service = UserService()
    
            cls.user.save()
    
        @classmethod
        def tearDownClass(cls):
            cls.connection.drop_database('mongoenginetest')
    
        def test_existing_user(self):
            user = self.user_service.existing_user(self.data['email'])
            self.assertIsNotNone(user)
    
            user_ko = self.user_service.existing_user("error@mail.fr")
            self.assertIsNone(user_ko)