2017-03-06 12 views
0

데이터베이스를 치지 않도록 장고 모델을 Factory 객체로 대체하려면 어떻게해야합니까?이 테스트 케이스에서 데이터베이스로의 이동을 피하는 방법

models.py

from django.db import models 

class ApplicationType(models.Model): 
    """ 
    Types of applications available in the system/ 
    """ 
    title = models.CharField(max_length=30) 

    def __str__(self): 
     return self.title 

utils.py

from .models import ApplicationType 

self.base_details = {} 

def get_application_type(self, value): 
""" 
Get types of applications. When successful it Populates the 
self.base_details with an application_type key 

Args: 
    value (object): value to be parsed 

Returns: 
    bool: True when value is ok, Else false 

Raises: 
""" 
item_name = "Application Type" 
self.base_details['application_type'] = None 
try: 
    if value: 
     try: 
      result = ApplicationType.objects.get(title=value) # <== How do I avoid hitting this DB object? 
      self.base_details['application_type'] = result.id 
      return True 
     except ApplicationType.DoesNotExist: 
      self.error_msg = "Invalid Value: {}".format(item_name) 
      return False 
    else: 
     self.error_msg = "Blank Value: {}".format(item_name) 
     return False 
except: 
    raise 

그래서 테스트하기 위해, 나는 ApplicationType 공장을 만들

tests.py

import factory 
import pytest 
application_types = ['Type 1', 'Type 2'] 

class ApplicationTypeFactory(factory.Factory): 
    class Meta: 
     model = ApplicationType 

    title = "application_type_title" 


@pytest.mark.django_db() 
def test_get_application_type_populates_dict_when_value_provided_exists_in_database(self): 
    """Populates base_details dict when value is found in database""" 
    for entry in application_types: 
     application_type = ApplicationTypeFactory.build(title=entry) 
     assert self.base_info_values.get_application_type(entry) == True 
     assert self.base_info_values.base_details["application_type"] is not None 

그렇다면 코드 중간에있는 ApplicationType.objects.get() 쿼리에서 데이터베이스를 치는 것을 피할 테스트를 작성하는 방법은 무엇입니까? 함수에 "Model"을 매개 변수로 전달할 수 있습니까? 그러면 좋은 디자인이 될까요?

특히 이러한 종류의 시나리오에서 더 나은 테스트를 수행 할 수 있도록 응용 프로그램/기능에 대한 대체 구조를 제공 할 수 있습니다.

당신은 당신이 설정 한 사전 정의 된 값을 반환하기 위해 데이터베이스에 전화를 패치 할 수 Python3.5, pytest - 장고와 factory_boy

답변

0

을 실행하고 있습니다. 귀하의 경우에는, 당신은 같은 것을 할 수있는 :

import factory 
import pytest 
from unittest.mock import Mock, patch 
application_types = ['Type 1', 'Type 2'] 
@pytest.mark.django_db() 
@patch('ApplicationType.objects.get') 
def test_get_application_type_populates_dict_when_value_provided_exists_in_database(self, db_mocked_call): 
    """Populates base_details dict when value is found in database""" 
    mocked_db_object = {'id': 'test_id'} 
    db_mocked_call.return_value = mocked_db_object 
    for entry in application_types: 
     application_type = ApplicationTypeFactory.build(title=entry) 
     assert self.base_info_values.get_application_type(entry) == True 
     assert self.base_info_values.base_details["application_type"] is not None 

난 당신이 테스트에 루프의 사용을 방지하기 위해 pytest.parametrize뿐만 아니라 확인하는 것이 좋습니다를, 여기에 대한 자세한 내용 : http://doc.pytest.org/en/latest/parametrize.html

예제에서 테스트는 다음과 같이 보일 수 있습니다.

@pytest.mark.django_db() 
@pytest.mark.parametrize("entry", ['Type 1', 'Type 2']) 
@patch('ApplicationType.objects.get') 
def test_get_application_type_populates_dict_when_value_provided_exists_in_database(self, db_mocked_call, entry): 
    """Populates base_details dict when value is found in database""" 
    mocked_db_object = {'id': 'test_id'} 
    db_mocked_call.return_value = mocked_db_object 
    application_type = ApplicationTypeFactory.build(title=entry) 
    assert self.base_info_values.get_application_type(entry) == True 
    assert self.base_info_values.base_details["application_type"] is not None