0

如何使用 Factory 对象覆盖 django 模型以避免访问数据库。

模型.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

实用程序.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 工厂

测试.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()代码中间的查询中命中数据库?我可以将“模型”作为参数传递给函数吗?这会是一个好的设计吗?

您可以自由地为应用程序/功能提供替代结构,特别是允许在这种情况下进行更好的测试。

我正在运行 Python3.5、pytest-django 和 factory_boy

4

1 回答 1

1

您可以修补对数据库的调用,以返回您设置的预定义值。在您的情况下,您可以执行以下操作:

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 以避免在你的测试中使用 for 循环,在这里阅读更多关于它的信息: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
于 2017-03-14T19:28:52.470 回答