programing

파이썬 유닛 테스트를 위해 mongodb를 조롱하는 방법은 무엇입니까?

madecode 2023. 7. 10. 23:33
반응형

파이썬 유닛 테스트를 위해 mongodb를 조롱하는 방법은 무엇입니까?

사용 중mockPython 2.7을 위한 모듈은 나의 다른 기능들을 조롱하고 사용합니다.

unittest쓰기 단위 테스트용입니다.

MongoDB를 조롱하는 것과 모의 기능을 사용하는 것이 다른지 궁금합니다(mock.patch호출되는 함수?)아니면 다른 패키지를 사용해야 합니까?

테스트 mongodb 인스턴스를 실행하고 싶지 않습니다.내가 원하는 것은 약간의 템포 데이터와 전화를 할 수 있는 것입니다.pymongo기능성나는 단지 모듈에 대한 모의 글을 쓰는 방법이 있을까 하는 생각에 약간 빠져 있습니다(예를 들어.pymongo) 또는 모든 것이 가능합니다.mock모듈.

이에 대한 예나 튜토리얼을 제공해 주시면 감사하겠습니다.

테스트할 코드

from pymongo import MongoClient

monog_url = 'mongodb://localhost:27017'
client = MongoClient(monog_url)
db = client.db

class Dao(object):
   def __init__(self):
      pass

   def save(self, user):
      db_doc = {
        'name': user.name,
        'email': user.email
      }
      db.users.save(db_doc)

   def getbyname(self, user):
      db_doc = {
        'name': user.name,
      }
      return db.users.find(db_doc)

이것을 테스트하기 위해, 저는 테스트 몽고드브가 가동되고 실행되는 것을 별로 원하지 않습니다!또한, 제가 저장한 데이터를 실제로 검색하여 DB에 있는지 확인하고 싶기 때문에 db.userssave 및 db.users.find를 모의하고 싶지 않습니다.제 기억 속에 있는 모델별로 고정장치를 만들어 작업해야 할 것 같습니다.외부 도구만 있으면 됩니까?

이런 가짜 자료를 보관하려고 하는데, 어떻게 처리해야 할지 모르겠어요.

users = { 
    {'name' : 'Kelly', 'email' : 'kelly@gmail.com'},
    {'name': 'Sam', 'email': 'sam@gmail.com'}
}

저는 몽고드를 조롱하기 위해 몽고드를 사용하는 것을 추천합니다.이것은 기본적으로 파이몬고 인터페이스를 가진 메모리 내 몽고드b이며 특별히 이 목적을 위해 만들어졌습니다.

https://github.com/mongomock/mongomock

필드별로 검색할 필요가 없는 단순한 작업을 수행하는 경우에도 이 작업을 수행할 수 있습니다.

@mock.patch("pymongo.collection.Collection.find")
def test_name(self, mock_find):
    mock_find.return_value = {'name' : 'Kelly', 'email' : 'kelly@gmail.com'}
    # rest of test

물론 PyMongo를 조롱할 수 있지만, MongoDB 서버 자체를 조롱하는 것을 추천합니다.MongoDB를 위한 순수 파이썬 에뮬레이터를 작성했습니다. MongoDB Wire Protocol 메시지에 완전히 제어할 수 있습니다. 어떤 방법을 선택하든 다음과 같습니다.

http://mockupdb.readthedocs.io/tutorial.html

다음은 Mockup을 사용하는 예입니다.Python 애플리케이션이 있는 DB:

https://emptysqua.re/blog/test-mongodb-failures-mockupdb/

MongoDB 와이어 프로토콜에 대한 깊은 지식이 필요하지만, 어쨌든 그것은 습득하기에 유용한 기술입니다.

@mirthbottle 답변에 추가하여 mongo 객체의 속성을 필드로 액세스하려면 다음과 같이 할 수 있습니다.

class MongoDummybject:
    def __init__(self, _data):
        for _d in _data:
            setattr(self, _d, _data[_d])

return_data = {'name' : 'Nishant', 'email' : 'nishant@gmail.com'}

@mock.patch("pymongo.collection.Collection.find")
def test_name(self, mock_find):
    mock_find.return_value = MongoDummybject(return_data)

사용자 지정 예외로 묶인 장치 테스트 예외의 경우 mongomock 컬렉션 내의 패치 함수(: bulk_write)

@mock.patch("mongomock.collection.Collection.bulk_write", side_effect=BulkWriteError({}))
def test_bulk_wrt_err(self, blk_wrt_err):
    with self.assertRaises(SpecialBulkWriteExcep) as context:
        add_user()

샘플 코드:

Mongomock은 테스트에 권장되는 방법입니다. 시작하기 위한 실행 가능한 예는 다음과 같습니다.

client.py

from dataclasses import dataclass

import pymongo

monog_url = 'mongodb://localhost:27018'
client = pymongo.MongoClient(monog_url)
db = client.db


@dataclass
class User:
    name: str
    email: str


class Dao:

    def save(self, db, user):
        db_doc = {
            'name': user.name,
            'email': user.email
        }
        return db.users.insert_one(db_doc).inserted_id

    def get_by_name(self, db, user):
        db_doc = {
            'name': user.name,
        }
        return db.users.find(db_doc)

test_client.파이의

import mongomock
import pytest

from client import Dao, User


class TestDao:

    @pytest.fixture
    def user(self):
        yield User(name='John', email='test@gmail.com')

    @pytest.fixture
    def dao(self):
        yield Dao()

    @pytest.fixture
    def client_mock(self):
        yield mongomock.MongoClient()

    @pytest.fixture
    def mock_db(self, client_mock):
        yield client_mock.db

    def test_save(self, mock_db, dao, user):
        id = dao.save(mock_db, user)

        users = list(mock_db.users.find())
        assert [obj for obj in users if obj['_id'] == id]
        assert len(users) == 1

    def test_get_by_name(self, mock_db, dao, user):
        dao.save(mock_db, user)
        found_user = next(dao.get_by_name(mock_db, user))
        found_user.pop('_id')
        assert found_user == user.__dict__

        unknown_user = User(name='Smith', email='john@gmail.com')
        found_user = next(dao.get_by_name(mock_db, unknown_user), None)
        assert found_user is None

@funnydman의 예를 사용합니다.

client.py

from pymongo import MongoClient


class MongoDB(object):
    def __init__(self) -> None:
        self.MONGO_URI ='mongodb://localhost:27018' 
        self.client = MongoClient(self.MONGO_URI)
        self.default_db = self.client.db

    def ingest_one(self, document: any, collection_name: str, db_name: str = None):

        if document:
            db_name = self.client[db_name] if db_name else self.default_db
            return db_name[collection_name].insert_one(document).inserted_id

    def find(self, query: dict, collection_name: str, db_name: str = None):
        db_name = self.client[db_name] if db_name else self.default_db
        return db_name[collection_name].find(query)

test_client.파이의

import mongomock
import pytest
import pytz
import datetime

from dataclasses import dataclass

from db.mongo_db import MongoDB


localtz = pytz.timezone('your_time_zone')


@dataclass
class Client:
    document: dict


class TestMongoDB:

    @pytest.fixture
    def client(self):
        yield Client(document={
            "name": "Juan Roman",
            "requestDate": str(datetime.datetime.now(localtz))
        })

    @pytest.fixture
    def mongo_db(self):
        yield MongoDB()

    @pytest.fixture
    def client_mock(self):
        yield mongomock.MongoClient()

    @pytest.fixture
    def mock_db(self, client_mock):
        yield client_mock.db

    def test_ingest_one(self, mock_db,  mongo_db, client):
        id_client = mongo_db.ingest_one(client.document, mock_db.collection.name, mock_db.name)
        stored_obj = mongo_db.find({'_id': id_client}, mock_db.collection.name, mock_db.name)

        assert [obj for obj in stored_obj if str(obj['_id']) == str(id_client)]

이 질문에 대한 가능한 대답으로 파이테스트모크 리소스에 대해 언급하고 싶은 사람이 있습니까?

개발 상자에 있는 도커에 따라 다르지만, 매번 컨테이너를 회전시킨다고 해서 속도가 느려질까 봐 걱정입니다.

저는 도커가 상태 저장을 허용한다고 생각하지만, 그것은 유닛 테스트의 dao를 위반하고, 테스트는 독립적이어야 하며 외부 자원에 의존하지 않아야 한다는 것입니다(가능하다면 도커도).

댓글은 환영합니다.

언급URL : https://stackoverflow.com/questions/42239241/how-to-mock-mongodb-for-python-unittests

반응형