Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在Django中修补多个ORM调用_Python_Django_Unit Testing_Orm - Fatal编程技术网

Python 在Django中修补多个ORM调用

Python 在Django中修补多个ORM调用,python,django,unit-testing,orm,Python,Django,Unit Testing,Orm,我在Django应用程序中有一个服务层,其中有一些业务逻辑和相应的数据检索代码。现在,当我编写单元测试时,我想模拟对ORM的调用,以便只测试服务层 我的服务层如下所示: from .models import Event class EventService(): def get_client_separated_events(self): # Some complex business logic goes here qs = Event.objec

我在Django应用程序中有一个服务层,其中有一些业务逻辑和相应的数据检索代码。现在,当我编写单元测试时,我想模拟对ORM的调用,以便只测试服务层

我的服务层如下所示:

from .models import Event

class EventService():

    def get_client_separated_events(self):
        # Some complex business logic goes here
        qs = Event.objects.all()
        # Some complex business logic here as well
        return foo
当我测试
EventService
类时,我希望完全模拟
Events.objects.all()
之类的调用。到目前为止,我正在使用
patch
来实现这一点:

class TestEventService(TestCase):

@classmethod
def setUpTestData(cls):
    cls.event_service = EventService()
    cls.dummy_events = [Event(id=1, name='n1', description='d1'), Event(id=2, name='n2', description='d2')]

@patch('foo.bar.Events.objects.all')
def test_get_all(self, get_events):
    get_events.return_value = self.dummy_events
    expected_events = self.event_service.get_all()
    self.assertListEqual(expected_Events, self.dummy_events, msg="Assertion failed for get_all method "
                                                                     "in Event Service")

然而,可能有十个这样不同的ORM调用,我不想写十行的
@patch
语句来模拟它们。我在网上看到,
@patch.multiple
可以做到这一点,但我不知道这是否是正确的方法。有人能帮忙吗

虽然您可以直接模拟ORM并返回任意结果,但我认为使用库(如)在数据库中插入假数据并保持ORM调用未被修改会更有效:

class EventFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = 'myapp.Event'


class TestEventService(TestCase):

    @classmethod
    def setUpTestData(cls):
        cls.event_service = EventService()

    def test_get_all(self):
        expected = [EventFactory() for i in range(10)]
        self.assertListEqual(
            self.event_service.get_all(),
            expected)
在某些情况下,您无法模拟所有内容,如果您模拟ORM调用,您可能最终通过了测试,而您的代码实际上是有缺陷的(例如,如果您的
过滤器
排除
语句中有错误)

如果您可以轻松地进行测试,并保持测试快速高效,我认为您应该避免嘲笑某些东西。在您的情况下:

  • 您可以轻松地创建虚拟数据
  • 如果您使用ORM,您的测试仍然会很快,因为Django在测试期间默认使用内存中的SQLite数据库,从而避免了磁盘I/O

不过,在其他情况下,模拟是完全有意义的,例如使用HTTP API通过网络检索数据。

在我们的项目中,我们试图确定何时模拟ORM层是一个好主意,何时不是。模拟ORM层使测试运行得更快,但测试更脆弱

在我看来,如果查询中存在任何复杂性,那么模仿ORM似乎是不值得的。您应该针对包含一些示例数据的测试数据库测试复杂的查询

如果您确实有一些简单的查询需要模拟,请尝试这个包。我提供了一个名为
mock_relations
的装饰程序,它模拟了您所询问的内容:
Event.objects
和外键关系

看一看显示如何使用它的。您可以列出几个要模拟的模型类

@mocked_relations(User)
class TestMockedApi(TestCase):
    def setUp(self):
        self.api = AnalyticsApi()

    def test_api_active_users_filters_by_is_active_true(self):
        active_user = MockModel(mock_name='active user', is_active=True)
        inactive_user = MockModel(mock_name='inactive user', is_active=False)

        User.objects.add(*[active_user, inactive_user])
        results = [x for x in self.api.active_users()]

        assert active_user in results
        assert inactive_user not in results