久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

如何在 Python 的單元測試場景中模擬 HTTP 請求

How to Mock an HTTP request in a unit testing scenario in Python(如何在 Python 的單元測試場景中模擬 HTTP 請求)
本文介紹了如何在 Python 的單元測試場景中模擬 HTTP 請求的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

我想為所有與 HTTP 相關的測試包括一個 Web 服務器.它不需要非常復雜.我寧愿不依賴于在線.所以我可以測試我的程序的一些選項.

I would like to include a Web server for all my test related to HTTP. It doesn't need to be very sophisticated. I would prefer not to be dependent of being online. So I could test some options of my program.

  1. 啟動服務器
  2. 使用適當的 mime 類型、響應代碼等創建一些資源 (URI).
  3. 運行測試(最好不必為每個測試啟動服務器)
  4. 關閉服務器.

有關此代碼的任何提示都會有所幫助.我用 BaseHTTPServer 嘗試了一些東西,但還沒有成功.nosetests 命令似乎無限期地等待.

Any hints on this code would be helpful. I tried a few things with BaseHTTPServer but not successful yet. nosetests command seems to wait indefinitely.

import unittest
from foo import core

class HttpRequests(unittest.TestCase):
    """Tests for HTTP"""

    def setUp(self):
        "Starting a Web server"
        self.port = 8080
        # Here we need to start the server
        #
        # Then define a couple of URIs and their HTTP headers
        # so we can test the code.
        pass

    def testRequestStyle(self):
        "Check if we receive a text/css content-type"
        myreq = core.httpCheck()
        myuri = 'http://127.0.0.1/style/foo'
        myua = "Foobar/1.1"
        self.asserEqual(myreq.mimetype(myuri, myua), "text/css")

    def testRequestLocation(self):
        "another test" 
        pass

    def tearDown(self):
        "Shutting down the Web server"
        # here we need to shut down the server
        pass

感謝您的幫助.

更新 - 2012:07:10T02:34:00Z

這是一個代碼,對于給定的網站將返回 CSS 列表.我想測試它是否返回正確的 CSS 列表.

This is a code which for a given Web site will return the list of CSS. I want to test if it returns the right list of CSS.

import unittest
from foo import core

class CssTests(unittest.TestCase):
    """Tests for CSS requests"""

    def setUp(self):
        self.css = core.Css()
        self.req = core.HttpRequests()

    def testCssList(self):
        "For a given Web site, check if we get the right list of linked stylesheets"
        WebSiteUri = 'http://www.opera.com/'
        cssUriList = [
        'http://www.opera.com/css/handheld.css',
        'http://www.opera.com/css/screen.css',
        'http://www.opera.com/css/print.css',
        'http://www.opera.com/css/pages/home.css']
        content = self.req.getContent(WebSiteUri)
        cssUriListReq = self.css.getCssUriList(content, WebSiteUri)
        # we need to compare ordered list.
        cssUriListReq.sort()
        cssUriList.sort()
        self.assertListEqual(cssUriListReq, cssUriList)

然后在 foo/core.py

import urlparse
import requests
from lxml import etree
import cssutils

class Css:
    """Grabing All CSS for one given URI"""


    def getCssUriList(self, htmltext, uri):
        """Given an htmltext, get the list of linked CSS"""
        tree = etree.HTML(htmltext)
        sheets = tree.xpath('//link[@rel="stylesheet"]/@href')
        for i, sheet in enumerate(sheets):
            cssurl = urlparse.urljoin(uri, sheet)
            sheets[i] = cssurl
        return sheets

目前,代碼依賴于在線服務器.它不應該.我希望能夠添加大量不同類型的樣式表組合并測試協議,然后在它們的解析、組合等方面進行一些選項.

Right now, the code depends on an online server. It should not. I want to be able to add plenty of different types of combination of stylesheets and to test the protocol and then later on some options on their parsing, combinations, etc.

推薦答案

為單元測試啟動 Web 服務器絕對不是一個好習慣.單元測試應該簡單且隔離,這意味著它們應該避免執行例如 IO 操作.

Starting a web server for unit testing is definitely not a good practice. Unit tests should be simple and isolated, which means that they should avoid performing IO operations for example.

如果您想編寫真正的單元測試,那么您應該制作自己的測試輸入并查看模擬對象.Python 作為一種動態語言,模擬和猴子路徑是編寫單元測試的簡單而強大的工具.特別是,看看優秀的 Mock 模塊.

If what you want to write are really unit tests then you should craft your own test inputs and also look into mock objects. Python being a dynamic language, mocking and monkey pathing are easy and powerful tools for writing unit test. In particular, have a look at the excellent Mock module.

因此,如果我們查看您的 CssTests 示例,您正在嘗試測試 css.getCssUriList 是否能夠提取片段中引用的所有 CSS 樣式表你給它的HTML.您在這個特定的單元測試中所做的并不是測試您可以發送請求并從網站獲得響應,對嗎?您只是想確保給定一些 HTML,您的函數返回正確的 CSS URL 列表.因此,在這個測試中,您顯然不需要與真正的 HTTP 服務器通信.

So, if we have a look at your CssTests example, you are trying to test that css.getCssUriList is able to extract all the CSS stylesheet referenced in a piece of HTML you give it. What you are doing in this particular unit test is not testing that you can send a request and get a response from a website, right? You simply want to make sure that given some HTML, your function returns the correct list of CSS URLs. So, in this test, you clearly do not need to talk to a real HTTP server.

我會做如下的事情:

import unittest

class CssListTestCase(unittest.TestCase):

    def setUp(self):
        self.css = core.Css()

    def test_css_list_should_return_css_url_list_from_html(self):
        # Setup your test
        sample_html = """
        <html>
            <head>
                <title>Some web page</title>
                <link rel='stylesheet' type='text/css' media='screen'
                       />
                <link rel='stylesheet' type='text/css' media='screen'
                      href='/styles/relative_url_style.css' />
            </head>
            <body><div>This is a div</div></body>
        </html>
        """
        base_url = "http://example.com/"

        # Exercise your System Under Test (SUT)
        css_urls = self.css.get_css_uri_list(sample_html, base_url)

        # Verify the output
        expected_urls = [
            "http://example.com/styles/full_url_style.css",
            "http://example.com/styles/relative_url_style.css"
        ]
        self.assertListEqual(expected_urls, css_urls)    

依賴注入模擬

現在,不太明顯的事情是對 core.HttpRequests 類的 getContent() 方法進行單元測試.我想您正在使用 HTTP 庫,而不是在 TCP 套接字上發出自己的請求.

Mocking with Dependency Injection

Now, something less obvious would be unit testing the getContent() method of your core.HttpRequests class. I suppose you are using an HTTP library and not making your own requests on top of TCP sockets.

為了使您的測試保持在 unit 級別,您不希望通過網絡發送任何內容.您可以做些什么來避免這種情況,即進行測試以確保您正確使用 HTTP 庫.這不是測試代碼的行為,而是測試它與周圍其他對象的交互方式.

To keep your tests at the unit level, you don't want to send anything over the wire. What you can do to avoid that, is having tests that ensure that you make use of your HTTP library correctly. This is about testing not the behaviour of your code but rather the way it interacts with the other objects around it.

這樣做的一種方法是明確對該庫的依賴:我們可以向 HttpRequests.__init__ 添加一個參數,以將一個庫的 HTTP 客戶端實例傳遞給它.假設我使用了一個提供 HttpClient 對象的 HTTP 庫,我們可以在該對象上調用 get().你可以這樣做:

One way to do so would be to make the dependency on that library explicit: we can add a parameter to the HttpRequests.__init__ to pass it an instance of library's HTTP client. Say I use an HTTP library that provides a HttpClient object on which we can call get(). You could do something like:

class HttpRequests(object):

    def __init__(self, http_client):
        self.http_client = http_client

   def get_content(self, url):
        # You could imagine doing more complicated stuff here, like checking the
        # response code, or wrapping your library exceptions or whatever
        return self.http_client.get(url)

我們已經明確了依賴關系,現在需要 HttpRequests 的調用者來滿足要求:這稱為依賴注入 (DI).

We have made the dependency explicit and the requirement now needs to be met by the caller of HttpRequests: this is called Dependency Injection (DI).

DI 在兩件事上非常有用:

DI is very useful for two things:

  1. 它避免了您的代碼秘密依賴某個對象存在于某處的意外情況
  2. 它允許編寫測試,根據測試的目標注入不同類型的對象

在這里,我們可以使用我們將提供給 core.HttpRequests 的模擬對象,并且它會在不知不覺中使用它,就好像它是真正的庫一樣.之后,我們可以測試交互是否按預期進行.

Here, we can use a mock object that we will give to core.HttpRequests and that it will use, unknowingly, as if it were the real library. After that, we can test that the interaction was conducted as expected.

import core

class HttpRequestsTestCase(unittest.TestCase):

    def test_get_content_should_use_get_properly(self):
        # Setup

        url = "http://example.com"

        # We create an object that is not a real HttpClient but that will have
        # the same interface (see the `spec` argument). This mock object will
        # also have some nice methods and attributes to help us test how it was used.
        mock_http_client = Mock(spec=somehttplib.HttpClient) 

        # Exercise

        http_requests = core.HttpRequests(mock_http_client)
        content = http_requests.get_content(url)

        # Here, the `http_client` attribute of `http_requests` is the mock object we
        # have passed it, so the method that is called is `mock.get()`, and the call
        # stops in the mock framework, without a real HTTP request being sent.

        # Verify

        # We expect our get_content method to have called our http library.
        # Let's check!
        mock_http_client.get.assert_called_with(url)

        # We can find out what our mock object has returned when get() was
        # called on it
        expected_content = mock_http_client.get.return_value
        # Since our get_content returns the same result without modification,
        # we should have received it
        self.assertEqual(content, expected_content)

我們現在已經測試了我們的 get_content 方法與我們的 HTTP 庫正確交互.我們已經定義了 HttpRequests 對象的邊界并對其進行了測試,這就是我們應該在單元測試級別進行的工作.該請求現在已掌握在該庫的手中,我們的單元測試套件當然不會負責測試該庫是否按預期工作.

We have now tested that our get_content method interacts correctly with our HTTP library. We have defined the boundaries of our HttpRequests object and tested them, and this is as far as we should go at the unit test level. The request is now in the hand of that library and it is certainly not the role of our unit test suite to test that the library works as expected.

現在假設我們決定使用出色的requests 庫.它的 API 更加程序化,它沒有提供我們可以抓取來發出 HTTP 請求的對象.相反,我們會導入模塊并調用它的 get 方法.

Now imagine that we decide to use the great requests library. Its API being more procedural, it does not present an object we can grab to make HTTP requests from. Instead, we would import the module and call its get method.

我們在 core.py 中的 HttpRequests 類將如下所示:

Our HttpRequests class in core.py would then look somethings like the following:

import requests

class HttpRequests(object):

    # No more DI in __init__

    def get_content(self, url):
        # We simply delegate the HTTP work to the `requests` module
        return requests.get(url)

沒有更多的 DI,所以現在,我們想知道:

No more DI, so now, we are left wondering:

  • 如何防止網絡交互發生?
  • 如何測試我是否正確使用了 requests 模塊?

您可以在這里使用動態語言提供的另一種奇妙但有爭議的機制:猴子補丁.我們將在運行時將 requests 模塊替換為我們制作并可以在測試中使用的對象.

This is where you can use another fantastic, yet controversial, mechanism that dynamic languages offer: monkey patching. We will replace, at runtime, the requests module with an object we craft and can use in our test.

我們的單元測試將如下所示:

Our unit test will then look something like:

import core

class HttpRequestsTestCase(unittest.TestCase):

    def setUp(self):
        # We create a mock to replace the `requests` module
        self.mock_requests = Mock()

        # We keep a reference to the current, real, module
        self.old_requests = core.requests

        # We replace the module with our mock
        core.requests = self.mock_requests

    def tearDown(self):
        # It is very important that each unit test be isolated, so we need
        # to be good citizen and clean up after ourselves. This means that
        # we need to put back the correct `requests` module where it was
        core.requests = self.old_requests

    def test_get_content_should_use_get_properly(self):
        # Setup

        url = "http://example.com"

        # Exercise
        http_client = core.HttpRequests()
        content = http_client.get_content(url)

        # Verify

        # We expect our get_content method to have called our http library.
        # Let's check!
        self.mock_requests.get.assert_called_with(url)

        # We can find out what our mock object has returned when get() was
        # called on it
        expected_content = self.mock_requests.get.return_value
        # Since our get_content returns the same result without modification,
        # we should have received
        self.assertEqual(content, expected_content)

為了使這個過程不那么冗長,mock 模塊有一個 patch 裝飾器來處理腳手架.然后我們只需要寫:

To make this process less verbose, the mock module has a patch decorator that looks after the scaffolding. We then only need to write:

import core

class HttpRequestsTestCase(unittest.TestCase):

    @patch("core.requests")
    def test_get_content_should_use_get_properly(self, mock_requests):
        # Notice the extra param in the test. This is the instance of `Mock` that the
        # decorator has substituted for us and it is populated automatically.

        ...

        # The param is now the object we need to make our assertions against
        expected_content = mock_requests.get.return_value

結論

保持單元測試的規模小、簡單、快速和獨立是非常重要的.依賴另一臺服務器運行的單元測試根本不是單元測試.為此,DI 是一種很好的實踐,而模擬對象則是一種很好的工具.

Conclusion

It is very important to keep unit test small, simple, fast, and self-contained. A unit test that relies on another server to be running is simply not a unit test. To help with that, DI is a great practice, and mock objects a great tool.

首先,要理解模擬的概念以及如何使用它們并不容易.像每個電動工具一樣,它們也可能在您的手中爆炸,例如讓您相信您已經測試過某些東西,而實際上您沒有.確保模擬對象的行為和輸入/輸出反映現實至關重要.

At first, it is not easy to get your head around the concept of mock and how to use them though. Like every power tool, they can also explode in your hands and for example make you believe you have tested something when in reality you have not. Making sure that the behaviour and input/output of mock objects reflects the reality is paramount.

鑒于我們從未在單元測試級別與真正的 HTTP 服務器進行過交互,因此編寫集成測試以確保我們的應用程序能夠與它將在現實生活中處理的那種服務器進行通信非常重要.我們可以使用專門為集成測試設置的成熟服務器來做到這一點,或者編寫一個人為的服務器.

Given that we have never interacted with a real HTTP server at the unit test level, it is important to write Integration Tests that will make sure our application is able to talk to the sort of servers it will deal with in real life. We could do this with a fully fledged server set up specially for Integration Testing, or write a contrived one.

這篇關于如何在 Python 的單元測試場景中模擬 HTTP 請求的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!

【網站聲明】本站部分內容來源于互聯網,旨在幫助大家更快的解決問題,如果有圖片或者內容侵犯了您的權益,請聯系我們刪除處理,感謝您的支持!

相關文檔推薦

How should I verify a log message when testing Python code under nose?(在鼻子下測試 Python 代碼時,我應該如何驗證日志消息?)
Patch __call__ of a function(修補函數的 __call__)
How to call self in a mock method of an object in Python?(如何在 Python 中對象的模擬方法中調用 self?)
Mocking only a single method on an object(僅模擬對象上的單個方法)
Mocking a subprocess call in Python(在 Python 中模擬子進程調用)
Checking call order across multiple mocks(檢查多個模擬的調用順序)
主站蜘蛛池模板: 一区视频在线免费观看 | 9色网站| 91精品国产综合久久久久久丝袜 | 亚洲国产一区在线 | 国产精品一区二区免费 | 精品毛片在线观看 | 黄色免费在线观看 | 国产精品一二三区 | 九一国产精品 | 国产色婷婷精品综合在线播放 | 免费同性女女aaa免费网站 | 日本天堂一区二区 | 91精品久久久久久久久久入口 | 久久中文字幕一区 | 日韩欧美视频免费在线观看 | 剑来高清在线观看 | 新超碰97| 中文字幕成人在线 | 一区二区三区在线 | 欧 | 精品一二三区视频 | 香蕉视频一区二区 | 国产精品视频在线播放 | 国产精品视频网 | 日韩国产一区二区三区 | 色一情一乱一伦一区二区三区 | 奇米影视在线 | av香蕉| 欧美精品久久久久久久久久 | 一级黄色绿像片 | 久久男人| 男人天堂网av | 影视先锋av资源噜噜 | av免费网| 在线观看免费国产 | 黄色大片免费网站 | 欧美在线视频网站 | 瑟瑟激情| 亚洲永久 | 亚洲一区久久久 | 在线激情视频 | 日韩欧美在线免费观看视频 |