2012-03-04 87 views
49

我寫使用肯尼斯·賴茨的requests library,我努力尋找一個很好的方式,單元測試這些應用程序執行REST操作的應用程序的請求Python應用程序,因爲請求通過模塊 - 提供其方法級別的方法。單元測試使用圖書館

我想是合成雙方之間的對話的能力;提供一系列請求斷言和響應。

+2

所以你需要模擬出REST服務器? – kgr 2012-03-04 23:57:26

+0

爲什麼這會使單元測試不適用?檢查庫如何進行自己的單元測試;可能會提供想法。 – 2012-03-05 01:00:09

+1

FWIW,請求庫使用實時URL(github.com,作者自己的域名等)進行自己的測試。 – Raumkraut 2012-11-28 13:29:12

回答

21

你可以用嘲弄的庫如Mocker攔截到請求庫調用和返回指定的結果。

作爲一個很簡單的例子,考慮這個類使用了請求庫:

class MyReq(object): 
    def doSomething(self): 
     r = requests.get('https://api.github.com', auth=('user', 'pass')) 
     return r.headers['content-type'] 

這裏有一個單元測試,攔截調用requests.get並返回測試特定的結果:

import unittest 
import requests 
import myreq 

from mocker import Mocker, MockerTestCase 

class MyReqTests(MockerTestCase): 
    def testSomething(self): 
     # Create a mock result for the requests.get call 
     result = self.mocker.mock() 
     result.headers 
     self.mocker.result({'content-type': 'mytest/pass'}) 

     # Use mocker to intercept the call to requests.get 
     myget = self.mocker.replace("requests.get") 
     myget('https://api.github.com', auth=('user', 'pass')) 
     self.mocker.result(result) 

     self.mocker.replay() 

     # Now execute my code 
     r = myreq.MyReq() 
     v = r.doSomething() 

     # and verify the results 
     self.assertEqual(v, 'mytest/pass') 
     self.mocker.verify() 

if __name__ == '__main__': 
    unittest.main() 

當我運行這個單元測試時,我得到以下結果:

. 
---------------------------------------------------------------------- 
Ran 1 test in 0.004s 

OK 
2

使用模仿者就像srgerg的回答是:

def replacer(method, endpoint, json_string): 
    from mocker import Mocker, ANY, CONTAINS 
    mocker = Mocker() 
    result = mocker.mock() 
    result.json() 
    mocker.count(1, None) 
    mocker.result(json_string) 
    replacement = mocker.replace("requests." + method) 
    replacement(CONTAINS(endpoint), params=ANY) 
    self.mocker.result(result) 
    self.mocker.replay() 

對於請求庫,這將攔截方法的要求和端點你打,並與傳入的json_string響應更換以.json()

38

如果您使用的具體要求嘗試httmock。這是非常簡單的優雅:

from httmock import urlmatch, HTTMock 
import requests 

# define matcher: 
@urlmatch(netloc=r'(.*\.)?google\.com$') 
def google_mock(url, request): 
    return 'Feeling lucky, punk?' 

# open context to patch 
with HTTMock(google_mock): 
    # call requests 
    r = requests.get('http://google.com/') 
print r.content # 'Feeling lucky, punk?' 

如果你想要的東西更通用的(例如嘲笑任何庫發出HTTP調用)去httpretty

幾乎一樣優雅:

import requests 
import httpretty 

@httpretty.activate 
def test_one(): 
    # define your patch: 
    httpretty.register_uri(httpretty.GET, "http://yipit.com/", 
         body="Find the best daily deals") 
    # use! 
    response = requests.get('http://yipit.com') 
    assert response.text == "Find the best daily deals" 

HTTPretty是更爲豐富的功能 - 它也提供嘲諷狀態碼,流媒體的反應,旋轉響應,動態響應(與回調)。

+0

這個httpretty的東西直接來自這個世界,謝謝! – mccc 2015-09-17 08:53:27

19

事實上,這是一個有些奇怪的是,圖書館擁有大約終端用戶單元測試一個空白頁,而針對用戶友好性和易用性。然而,Dropbox有一個易於使用的庫,不出意外地稱爲responses。這是它的intro post。它說他們沒有僱用httpretty,但沒有說明失敗的原因,並且寫了一個類似API的庫。

import unittest 

import requests 
import responses 


class TestCase(unittest.TestCase): 

    @responses.activate 
    def testExample(self): 
    responses.add(**{ 
     'method'   : responses.GET, 
     'url'   : 'http://example.com/api/123', 
     'body'   : '{"error": "reason"}', 
     'status'   : 404, 
     'content_type' : 'application/json', 
     'adding_headers' : {'X-Foo': 'Bar'} 
    }) 

    response = requests.get('http://example.com/api/123') 

    self.assertEqual({'error': 'reason'}, response.json()) 
    self.assertEqual(404, response.status_code) 
+0

「響應」的更新網址[** intro post **](http://cra.mr/2014/05/20/mocking-requests-with-responses) – 2018-02-21 10:19:37

0

這些答案的缺失是requests-mock

從他們的網頁:

>>> import requests 
>>> import requests_mock 

由於上下文經理:

>>> with requests_mock.mock() as m: 

...  m.get('http://test.com', text='data') 
...  requests.get('http://test.com').text 
... 
'data' 

或者作爲裝飾:

>>> @requests_mock.mock() 
... def test_func(m): 
...  m.get('http://test.com', text='data') 
...  return requests.get('http://test.com').text 
... 
>>> test_func() 
'data' 
+0

您是否有任何關於如何進行此操作的知識使用''pytest''工作?我嘗試了你引用的確切例子。 Ref .: https://stackoverflow.com/questions/47703748/why-does-the-simplest-requests-mock-example-fail-with-pytest – 2017-12-08 00:59:19

+0

如果我沒記錯的話,我使用了裝飾器。我認爲這也適用於pytest。 – Unapiedra 2017-12-18 16:08:02

+0

我使用裝飾器工作,但它似乎(在我的系統上)它與其他參數衝突,所以我必須將kw參數傳遞給Mocker,如[docs](https:// requests- mock.readthedocs.io/en/latest/mocker.html#decorator)。不知道這是否與pytest有關,但出現的錯誤提到了夾具。感謝您回到問題。 – 2017-12-18 17:37:24