Как издеваться над mongodb, когда он вызывается из другой функции?

Мне нужна помощь, пока я издеваюсь над mongodb. Я использую монгомок, чтобы издеваться над mongodb.

Моя структура проекта:

-- my_mongo.py
-- code.py
-- my_test.py

my_mongo.py имеет:

from pymongo import MongoClient

 def get_db():
   client = MongoClient(os.environ['MONGODB_URI'])
   db = client['my_db']
   return db

 def insert(id, data):
     return get_db().results.insert_one(
          {
          "id": id,
          "data":df.to_json(),
          }).id

и code.py имеет

import my_mongo

def action():
    #do somethings
    my_mongo.insert(id, data)

и my_test.py имеет

import mongomock
import my_mongo
from unittest import mock


with patch.object(my_mongo.get_db().client, "client",  mongomock.MongoClient()):
    import code

def test_action_1():
    my_mongo.insert = mock.Mock(return_value=1)
    code.action()   

def test_action_2():
     with patch.object(my_mongo.get_db(), "get_db", mongomock.MongoClient().db):
     code.action()

Он выбрасывает pymongo.errors.ServerSelectionTimeoutError для обоих тестов. Итак, он по-прежнему входит в метод insert_one () в my_mongo.py. Я ожидаю, что в test_action_1 my_mongo.insert вернет 1, но это не так.

Что мне не хватает?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
2 370
2

Ответы 2

Я не совсем уверен, для чего нужен mongomock, но похоже, что он насмехается над всей базой данных mongo, а не использует насмешку с Python. Я собираюсь ответить, не включая mongomock, так как я не думаю, что он вам действительно нужен, так что вы можете принять это за то, что оно того стоит.

Было несколько проблем:

  1. Вызов patch.object исправит данный метод на любом объекте, который вы ему передадите. Если вы вызываете get_db в тесте, то code.action вызывает get_db, это 2 разных объекта. Может это работает? Но я настроен скептически, поэтому просто изменил это.

  2. Не используйте code в качестве имени вашего модуля. Это уже модуль, включенный в python.

  3. В code.action отсутствовали аргументы и оператор возврата.

Вы также заметите, что я изменил то, как и что насмехались, чтобы проиллюстрировать различные способы выполнения насмешек. Тест 1 имитирует вызов insert с помощью декоратора функций. Тест 2 имитирует вызов get_db с помощью contextmanager. Либо правильно, просто показывая, что у вас есть варианты.

Вот и готовый продукт:


my_mongo.py:

from pymongo import MongoClient

def get_db():
    client = MongoClient(os.environ['MONGODB_URI'])
    db = client['my_db']
    return db

def insert(id, data):
    return get_db().results.insert_one({"id": id, "data":data.to_json()}).id  # df was undefined, updated to data

my_code.py:

import my_mongo

# I added id and data args. They were undefined
def action(id, data):
    return my_mongo.insert(id, data)  # I added a return here

my_test.py

from unittest import mock

import my_code

# I removed the contextmanager import. Nothing is being evaluated here that would
# need to be patched, so I'm pretty certain it has no effect

@mock.patch('my_mongo.insert')
def test_action_1(mock_insert):
    expected_id = 1
    mock_insert.return_value = expected_id
    ret = my_code.action(expected_id, mock.Mock())
    assert ret == expected_id

def test_action_2():
    with mock.patch('my_mongo.get_db') as mock_get_db:
        expected_id = 'some id'
        mock_db = mock.Mock()
        mock_db.results.insert_one.return_value.id = expected_id
        mock_get_db.return_value = mock_db
        ret = my_code.action(expected_id, mock.Mock())
    assert ret == expected_id

Эта строка кода для исправления mongodb неверна. Вместо patch.object(my_mongo.get_db(), "get_db", mongomock.MongoClient().db) вы должны использовать patch.object("my_mongo.get_db", return_value=mongomock.MongoClient()['my_db']).


Ниже приведен полный исполняемый код для вашего примера:

my_test.py

import mongomock
from unittest.mock import patch

import my_code
import my_mongo


def test_action_2():
    mocked_mongo = mongomock.MongoClient()
    with patch("my_mongo.get_db", return_value=mongomock.MongoClient()['my_db']):
        my_code.action()
        assert mocked_mongo.my_db.results.count_documents({'id': 'some_id'}) == 1

my_mongo.py

from pymongo import MongoClient

def get_db():
    client = MongoClient(os.environ['MONGODB_URI'])
    db = client['my_db']
    return db

def insert(id, data):
    return get_db().results.insert_one(
        {
            "id": id,
            "data": data,
        })

my_code.py

import my_mongo

def action():
    #do somethings
    return my_mongo.insert('some_id', '{"a": 3}')

Другие вопросы по теме