Django写模拟测试

时间:2014-03-25 12:38:16

标签: python django unit-testing mocking

我在理解模拟如何工作以及如何使用模拟对象编写单元测试时遇到问题。我想模拟一个外部api调用,这样我就可以为这些使用这些调用的函数和函数编写单元测试。

我首先尝试模拟check_sms_request,然后我需要用它做一些事情来覆盖对象的check_delivery_status。

如何为这种情况编写测试?

模拟

的功能
def check_sms_request(remote_id, phone):
    if not can_sms(phone):
        return None

    client = Client(settings.SMS_API_URL)

    base_kwargs = {
        'phone': phone,
        'remoteId': remote_id,
    }
    request = client.service.CheckSmsRequest(settings.SMS_API_LOGIN, settings.SMS_API_PASSWORD, base_kwargs)

    return request

class SMS(models.Model):
    sms_response = models.IntegerField(choices=SMS_SEND_STATUS, null=True, blank=True)
    delivery_status = models.IntegerField(choices=DELIVERY_STATUS_CHOICES, null=True, blank=True)
    has_final_status = models.BooleanField(default=False)

    def check_delivery_status(self):
        if not self.has_final_status:
            response_status = check_sms_request(self.id, self.phone)
            if response_status is not None:
                self.history.create(fbs_status=self.sms_response, delivery_status=response_status.response)
            if response_status is not None and response_status.response in FINAL_STATUSES:
                self.has_final_status = True
            if response_status is not None:
                self.delivery_status = response_status.response
            self.save()
        return self.delivery_status

我的测试:

@override_settings(SMS_WHITELIST=['', ], SMS_ENABLE=True)
def test_soap_check_sms_request(self):
    check_sms_request = Mock(return_value=True)
    check_sms_request.response = SMS_SENT_AND_RECIEVED
    self.assertEqual(check_sms_request.response, SMS_SENT_AND_RECIEVED)

    obj = SMS.objects.create(**{
        'phone': self.user.phone,
        'text': u"Hello",
        'user': self.user,
        'site': self.site2,
    })
    obj.check_sms_status()

2 个答案:

答案 0 :(得分:0)

您可以对测试功能进行猴子修补,如下所示:

@override_settings(SMS_WHITELIST=['', ], SMS_ENABLE=True)
def test_soap_check_sms_request(self):
    check_sms_request = Mock(return_value=True)
    check_sms_request.response = SMS_SENT_AND_RECIEVED
    self.assertEqual(check_sms_request.response, SMS_SENT_AND_RECIEVED)

    obj = SMS.objects.create(**{
        'phone': self.user.phone,
        'text': u"Hello",
        'user': self.user,
        'site': self.site2,
    })

    import model
    old_fn = model.check_sms_request
    model.check_sms_request = check_sms_request
    obj.check_sms_status()
    model.check_sms_request = old_fn

答案 1 :(得分:0)

  1. 首先测试check_sms_request
    1. 模拟客户端
    2. 使用return_value
    3. 的retrive服务和CheckSmsRequest模拟
    4. call check_sms_request
    5. 检查客户端和CheckSmsRequest是否使用右args
    6. 调用一次
  2. check_sms_request应该是类的方法,在SMS模型中移动它或者只是添加方法并从这个方法中调用函数
  3. 在测试check_delivery_status
  4. 时模拟此模型方法

    型号:

    class SMS(models.Model):
        sms_response = models.IntegerField(choices=SMS_SEND_STATUS, null=True, blank=True)
        delivery_status = models.IntegerField(choices=DELIVERY_STATUS_CHOICES, null=True, blank=True)
        has_final_status = models.BooleanField(default=False)
    
        def check_sms_request(remote_id, phone):
            if not can_sms(phone):
                return None
    
            client = Client(settings.SMS_API_URL)
    
            base_kwargs = {
                'phone': phone,
                'remoteId': remote_id,
            }
            request = client.service.CheckSmsRequest(settings.SMS_API_LOGIN, settings.SMS_API_PASSWORD, base_kwargs)
    
            return request
    
        def check_delivery_status(self):
            if not self.has_final_status:
                response_status = self.check_sms_request(self.id, self.phone)
                if response_status is not None:
                    self.history.create(fbs_status=self.sms_response, delivery_status=response_status.response)
                if response_status is not None and response_status.response in FINAL_STATUSES:
                    self.has_final_status = True
                if response_status is not None:
                    self.delivery_status = response_status.response
                self.save()
            return self.delivery_status
    

    测试:

    class SMSModelTestCase(TestCase):
    
        @patch('...Client')
        def test_check_sms_request(self, ClientMock):
            client_object = ClientMock.return_value
            CheckSmsRequestMock = client_object.service.return_value.CheckSmsRequest
            sms_model = SMS() # don't save
            with self.settings(SMS_API_URL='http://example.com', SMS_API_LOGIN='kanata', SMS_API_PASSWORD='izumi'):
                sms_model.check_sms_request(101, '+11111111')
            ClientMock.assert_called_once_with('http://example.com')
            CheckSmsRequestMock.assert_called_once_with('kanata', 'izumi', '+11111111', 101)
    
        @patch('myproject.myapp.models.SMS.check_sms_request')
        def test_check_delivery_status(self, CheckSmsRequestMock):
            CheckSmsRequestMock.return_value = ...
            sms_model = SMS()
            ...
            sms_model.check_delivery_status(...)