pymongo.MongoClient being created instead of mongomock.MongoClient

86 views Asked by At

When I tried to run my test it tries to create a real conection with MongoDB instead of using mongomock.

This stop happening when I remove the "from .main import HashClient" from my init.py.

my project is:

hash_controller/

|

|----> init.py

|----> hash_controller.py

|----> test_hash_controller.py

My init.py is:

`from .main import HashClient`

My hash_controller is:


    import hashlib
    import json
    import os
    import time


    def get_connection():
        _db_user = os.environ["HASH_DB_USER"]
        _db_password = os.environ["HASH_DB_PASS"]
        _db_host = os.environ["HASH_DB_HOST"]
        _db_port = os.environ["HASH_DB_PORT"]
        _db_name = os.environ["HASH_DB_NAME"]
        _db_collection = os.environ["HASH_DB_COLLECTION"]

        # _client = MongoClient(f"mongodb://{_db_user}:{_db_password}@{_db_host}:{_db_port}/")
        from pymongo import MongoClient
        _client = MongoClient(f"mongodb://{_db_host}:{_db_port}/")
        _database = _client[_db_name]
        _collection = _database[_db_collection]
        return _collection


    class HashClient:

        @staticmethod
        def exist(customer_uuid: str, type: str, obj):
            HashClient._check_customer_and_type(customer_uuid, type)
            HashClient._check_obj(obj)
            id = HashClient._get_hash(customer_uuid, type, obj)
            collection = get_connection()
            item = collection.find_one(id)
            if item is None:
                return False
            else:
                return True

and my test is:

    import os
    import mongomock

    os.environ["HASH_DB_USER"]=""
    os.environ["HASH_DB_PASS"]=""
    os.environ["HASH_DB_HOST"]="localhost"
    os.environ["HASH_DB_PORT"]="27017"
    os.environ["HASH_DB_NAME"]="test"
    os.environ["HASH_DB_COLLECTION"]="test"

    with mongomock.patch(servers=(('localhost', 27017),)):
        import pymongo
        client = pymongo.MongoClient("localhost")
        from .main import HashClient


    def test_exist_false():
        hash = HashClient._get_hash("123", "user", {"user": "222"})
        client["test"]["test"].insert_one({"_id": hash})
        response = HashClient.exist("123", "user", {"user": "123"})
        assert response == False
        client.test.test.delete_many({})

I tried moving all the imports inside the function so they don't get executed when running the test, but anything helps. The idea is to run the test with the import from the init.py

1

There are 1 answers

0
Ehsan On

In the last test function def test_exist_false(), mocked mongo client which is created in the whit block is called to save data.
client["test"]["test"].insert_one({"_id": hash})
It is mocked client, no problem. but HashClient.exist() does not use it, it even has no access to the mocked client.

Why HashClient.exist() has not access to mocked client?
because it creates collection itself inside itself. the problem is that the collection which is created in exist() function is not mocked, it's the real collection.

Better to split the file hash_controller.py to two files. a file for get_collection() and another one for class HashClient.
HashClient can set collection in method __init__() or set_collection() or etc.

So it will be possible to set the mocked collection for HashClient in tests.

Edit:
setting mock db config in os.environ should work too. Because the function get_collection() uses the config after setting it in the test file, I've no idea about imports and about why it doesn't work.
But at least to split hash_controller.py can increase software cohesion and independence of tests.