【问题标题】:Django writing mock testDjango编写模拟测试
【发布时间】:2014-03-25 12:38:16
【问题描述】:

我在理解模拟如何工作以及如何使用模拟对象编写单元测试时遇到问题。我想模拟一个外部 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()

【问题讨论】:

    标签: python django unit-testing mocking


    【解决方案1】:

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

    @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
    

    【讨论】:

      【解决方案2】:
      1. 首先测试 check_sms_request
        1. 模拟客户端
        2. 使用 return_value 检索服务和 CheckSmsRequest 模拟
        3. 调用 check_sms_request
        4. check Client 和 CheckSmsRequest 被调用一次,参数正确
      2. check_sms_request 应该是一个类的方法,将它移动到 SMS 模型中或者只是添加方法并从这个方法调用函数
      3. 在测试 check_delivery_status 时模拟此模型方法

      型号:

      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(...)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-20
        • 2023-03-04
        相关资源
        最近更新 更多