我的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并返回任意结果,但我认为使用factory_boy之类的数据库在数据库中插入伪数据并使其不被模拟会更有效:

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调用,则可能会在代码实际上有错误时(例如,如果您的filterexclude语句有错误)通过测试。

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


您可以轻松创建虚拟数据
如果使用ORM,则测试仍将很快,因为Django默认在测试过程中使用内存中的SQLite数据库来避免磁盘I / O。


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

关于python - 在Django中修补多个ORM调用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42251670/

10-15 18:34