pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

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

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

問題描述

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

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. 啟動服務(wù)器
  2. 使用適當(dāng)?shù)?mime 類型、響應(yīng)代碼等創(chuàng)建一些資源 (URI).
  3. 運行測試(最好不必為每個測試啟動服務(wù)器)
  4. 關(guān)閉服務(wù)器.

有關(guān)此代碼的任何提示都會有所幫助.我用 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

這是一個代碼,對于給定的網(wǎng)站將返回 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

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

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 服務(wù)器絕對不是一個好習(xí)慣.單元測試應(yīng)該簡單且隔離,這意味著它們應(yīng)該避免執(zhí)行例如 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.

如果您想編寫真正的單元測試,那么您應(yīng)該制作自己的測試輸入并查看模擬對象.Python 作為一種動態(tài)語言,模擬和猴子路徑是編寫單元測試的簡單而強大的工具.特別是,看看優(yōu)秀的 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.您在這個特定的單元測試中所做的并不是測試您可以發(fā)送請求并從網(wǎng)站獲得響應(yīng),對嗎?您只是想確保給定一些 HTML,您的函數(shù)返回正確的 CSS URL 列表.因此,在這個測試中,您顯然不需要與真正的 HTTP 服務(wù)器通信.

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)    

依賴注入模擬

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

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 級別,您不希望通過網(wǎng)絡(luò)發(fā)送任何內(nèi)容.您可以做些什么來避免這種情況,即進(jìn)行測試以確保您正確使用 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__ 添加一個參數(shù),以將一個庫的 HTTP 客戶端實例傳遞給它.假設(shè)我使用了一個提供 HttpClient 對象的 HTTP 庫,我們可以在該對象上調(diào)用 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)

我們已經(jīng)明確了依賴關(guān)系,現(xiàn)在需要 HttpRequests 的調(diào)用者來滿足要求:這稱為依賴注入 (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. 它允許編寫測試,根據(jù)測試的目標(biāo)注入不同類型的對象

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

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)

我們現(xiàn)在已經(jīng)測試了我們的 get_content 方法與我們的 HTTP 庫正確交互.我們已經(jīng)定義了 HttpRequests 對象的邊界并對其進(jìn)行了測試,這就是我們應(yīng)該在單元測試級別進(jìn)行的工作.該請求現(xiàn)在已掌握在該庫的手中,我們的單元測試套件當(dāng)然不會負(fù)責(zé)測試該庫是否按預(yù)期工作.

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.

現(xiàn)在假設(shè)我們決定使用出色的requests 庫.它的 API 更加程序化,它沒有提供我們可以抓取來發(fā)出 HTTP 請求的對象.相反,我們會導(dǎo)入模塊并調(diào)用它的 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,所以現(xiàn)在,我們想知道:

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

  • 如何防止網(wǎng)絡(luò)交互發(fā)生?
  • 如何測試我是否正確使用了 requests 模塊?

您可以在這里使用動態(tài)語言提供的另一種奇妙但有爭議的機制:猴子補丁.我們將在運行時將 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

結(jié)論

保持單元測試的規(guī)模小、簡單、快速和獨立是非常重要的.依賴另一臺服務(wù)器運行的單元測試根本不是單元測試.為此,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.

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

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 服務(wù)器進(jìn)行過交互,因此編寫集成測試以確保我們的應(yīng)用程序能夠與它將在現(xiàn)實生活中處理的那種服務(wù)器進(jìn)行通信非常重要.我們可以使用專門為集成測試設(shè)置的成熟服務(wù)器來做到這一點,或者編寫一個人為的服務(wù)器.

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.

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

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

相關(guān)文檔推薦

How should I verify a log message when testing Python code under nose?(在鼻子下測試 Python 代碼時,我應(yīng)該如何驗證日志消息?)
Patch __call__ of a function(修補函數(shù)的 __call__)
How to call self in a mock method of an object in Python?(如何在 Python 中對象的模擬方法中調(diào)用 self?)
Mocking only a single method on an object(僅模擬對象上的單個方法)
Mocking a subprocess call in Python(在 Python 中模擬子進(jìn)程調(diào)用)
Checking call order across multiple mocks(檢查多個模擬的調(diào)用順序)
主站蜘蛛池模板: 吉祥新世纪铝塑板_生产铝塑板厂家_铝塑板生产厂家_临沂市兴达铝塑装饰材料有限公司 | 化工ERP软件_化工新材料ERP系统_化工新材料MES软件_MES系统-广东顺景软件科技有限公司 | 科威信洗净科技,碳氢清洗机,超声波清洗机,真空碳氢清洗机 | 北京企业宣传片拍摄_公司宣传片制作-广告短视频制作_北京宣传片拍摄公司 | 招商帮-一站式网络营销服务|互联网整合营销|网络推广代运营|信息流推广|招商帮企业招商好帮手|搜索营销推广|短视视频营销推广 | 液晶拼接屏厂家_拼接屏品牌_拼接屏价格_监控大屏—北京维康 | 刺绳_刀片刺网_刺丝滚笼_不锈钢刺绳生产厂家_安平县浩荣金属丝网制品有限公司-安平县浩荣金属丝网制品有限公司 | 河南正规膏药生产厂家-膏药贴牌-膏药代加工-修康药业集团官网 | 不锈钢搅拌罐_高速搅拌罐厂家-无锡市凡格德化工装备科技有限公司 | 成都茶楼装修公司 - 会所设计/KTV装修 - 成都朗煜装饰公司 | 工业机械三维动画制作 环保设备原理三维演示动画 自动化装配产线三维动画制作公司-南京燃动数字 聚合氯化铝_喷雾聚氯化铝_聚合氯化铝铁厂家_郑州亿升化工有限公司 | LED投光灯-工矿灯-led路灯头-工业灯具 - 山东普瑞斯照明科技有限公司 | KBX-220倾斜开关|KBW-220P/L跑偏开关|拉绳开关|DHJY-I隔爆打滑开关|溜槽堵塞开关|欠速开关|声光报警器-山东卓信有限公司 | 上海租奔驰_上海租商务车_上海租车网-矢昂汽车服务公司 | 昆明挖掘机修理厂_挖掘机翻新再制造-昆明聚力工程机械维修有限公司 | 日本东丽膜_反渗透膜_RO膜价格_超滤膜_纳滤膜-北京东丽阳光官网 日本细胞免疫疗法_肿瘤免疫治疗_NK细胞疗法 - 免疫密码 | 厂房出租_厂房出售_产业园区招商_工业地产&nbsp;-&nbsp;中工招商网 | 自动气象站_气象站监测设备_全自动气象站设备_雨量监测站-山东风途物联网 | 湖南自考_湖南自学考试| 无菌实验室规划装修设计-一体化实验室承包-北京洁净净化工程建设施工-北京航天科恩实验室装备工程技术有限公司 | 哈尔滨治「失眠/抑郁/焦虑症/精神心理」专科医院排行榜-京科脑康免费咨询 一对一诊疗 | 在线钠离子分析仪-硅酸根离子浓度测定仪-油液水分测定仪价格-北京时代新维测控设备有限公司 | 泰州物流公司_泰州货运公司_泰州物流专线-东鑫物流公司 | 在线PH计-氧化锆分析仪-在线浊度仪-在线溶氧仪- 无锡朝达 | 电位器_轻触开关_USB连接器_广东精密龙电子科技有限公司 | 包装机_厂家_价格-山东包装机有限公司| 菲希尔FISCHER测厚仪-铁素体检测仪-上海吉馨实业发展有限公司 | 合肥通道闸-安徽车牌识别-人脸识别系统厂家-安徽熵控智能技术有限公司 | 99文库_实习生实用的范文资料文库站| 锡膏喷印机-全自动涂覆机厂家-全自动点胶机-视觉点胶机-深圳市博明智控科技有限公司 | 减速机三参数组合探头|TSM803|壁挂式氧化锆分析仪探头-安徽鹏宸电气有限公司 | 找培训机构_找学习课程_励普教育| 等离子表面处理机-等离子表面活化机-真空等离子清洗机-深圳市东信高科自动化设备有限公司 | 上海小程序开发-上海小程序制作公司-上海网站建设-公众号开发运营-软件外包公司-咏熠科技 | 领先的大模型技术与应用公司-中关村科金| 分子精馏/精馏设备生产厂家-分子蒸馏工艺实验-新诺舜尧(天津)化工设备有限公司 | 热熔胶网膜|pes热熔网膜价格|eva热熔胶膜|热熔胶膜|tpu热熔胶膜厂家-苏州惠洋胶粘制品有限公司 | 闸阀_截止阀_止回阀「生产厂家」-上海卡比阀门有限公司 | 山东太阳能路灯厂家-庭院灯生产厂家-济南晟启灯饰有限公司 | 篷房|仓储篷房|铝合金篷房|体育篷房|篷房厂家-华烨建筑科技官网 知名电动蝶阀,电动球阀,气动蝶阀,气动球阀生产厂家|价格透明-【固菲阀门官网】 | 北京发电机出租_发电机租赁_北京发电机维修 - 河北腾伦发电机出租 |