2013-08-02 67 views
7

我是新來嘲笑和我編寫單元測試這一功能:Django的單元測試和嘲弄請求模塊

# utils.py 
import requests  

def some_function(user): 
    payload = {'Email': user.email} 
    url = 'http://api.example.com' 
    response = requests.get(url, params=payload)  

    if response.status_code == 200: 
     return response.json() 
    else: 
     return None 

我使用Michael Foord's Mock庫作爲我的單元測試的一部分,我有困難的嘲諷response.json()返回一個json結構。這裏是我的單元測試:

# tests.py 
from .utils import some_function 

class UtilsTestCase(unittest.TestCase): 
    def test_some_function(self): 
     with patch('utils.requests') as mock_requests: 
      mock_requests.get.return_value.status_code = 200 
      mock_requests.get.return_value.content = '{"UserId":"123456"}' 
      results = some_function(self.user) 
      self.assertEqual(results['UserId'], '123456') 

我已經沒有運氣閱讀文檔後,嘗試了不同的模擬設置的多種組合。如果我在單元測試打印results它總是顯示以下,而不是JSON數據結構,我想:什麼我做錯了

<MagicMock name=u'requests.get().json().__getitem__().__getitem__()' id='30315152'> 

的思考?

回答

13

修補程序json方法而不是content。 (content未在some_function中使用)

請嘗試下面的代碼。

import unittest 

from mock import Mock, patch 

import utils 

class UtilsTestCase(unittest.TestCase): 
    def test_some_function(self): 
     user = self.user = Mock() 
     user.email = '[email protected]' 
     with patch('utils.requests') as mock_requests: 
      mock_requests.get.return_value = mock_response = Mock() 
      mock_response.status_code = 200 
      mock_response.json.return_value = {"UserId":"123456"} 
      results = utils.some_function(self.user) 
      self.assertEqual(results['UserId'], '123456') 
+0

這個答案非常感謝。它現在正如我所希望的那樣工作。 –

+0

我將添加到單元測試中的另一個斷言測試將確保request.get方法以期望的參數調用。就像''mock_get.assert_called_with('http://api.example.com',payload = {'Email':self.user.email}'這可以確保您的庫代碼正在使用期望的參數進行請求調用,這與測試庫代碼的返回值一樣重要,該值被嘲笑。 – adam

1

另一種模式,我喜歡的是使用多一點的可重複使用的是開始在你的單元測試的方法setUp修補器。同樣重要的是檢查模擬請求被稱爲與預期的參數:

class UtilsTestCase(TestCase): 

    def setUp(self): 
     self.user = Mock(id=123, email='[email protected]') 

     patcher = patch('utils.requests.get') 
     self.mock_response = Mock(status_code=200) 
     self.mock_response.raise_for_status.return_value = None 
     self.mock_response.json.return_value = {'UserId': self.user.id} 
     self.mock_request = patcher.start() 
     self.mock_request.return_value = self.mock_response 

    def tearDown(self): 
     self.mock_request.stop() 

    def test_request(self): 
     results = utils.some_function(self.user) 

     self.assertEqual(results['UserId'], 123) 

     self.mock_request.assert_called_once_with(
      'http://api.example.com' 
      payload={'Email': self.user.email}, 
     ) 

    def test_bad_request(self): 
     # override defaults and reassign 
     self.mock_response.status_code = 500 
     self.mock_request.return_value = self.mock_response 
     results = utils.some_function(self.user) 

     self.assertEqual(results, None) 

     self.mock_request.assert_called_once_with(
      'http://api.example.com' 
      payload={'Email': user.email}, 
     ) 
0

的另一種方式,我認爲更清晰和直接的:

import unittest 

from mock import Mock, patch 

import utils 

class UtilsTestCase(unittest.TestCase): 
    def test_some_function(self): 
     mock_response = Mock() 
     mock_response.status_code = 200 
     mock_response.json.return_value = {"UserId": "123456"} 
     with patch('utils.requests.get') as mock_requests: 
      results = utils.some_function(self.user) 
      self.assertEqual(results['UserId'], '123456')