摘要:每個測試方法的名稱以單詞開頭,單元測試是如何識別它們是測試的。它還意味著知道測試文件中有多少單元測試,而不是簡單地知道有多少表達式您可能已經(jīng)注意到將每個行作為多帶帶的測試計數(shù)。
來源 | 愿碼(ChainDesk.CN)內(nèi)容編輯
愿碼Slogan | 連接每個程序員的故事
網(wǎng)站 | http://chaindesk.cn
愿碼愿景 | 打造全學(xué)科IT系統(tǒng)免費課程,助力小白用戶、初級工程師0成本免費系統(tǒng)學(xué)習(xí)、低成本進階,幫助BAT一線資深工程師成長并利用自身優(yōu)勢創(chuàng)造睡后收入。
官方公眾號 | 愿碼 | 愿碼服務(wù)號 | 區(qū)塊鏈部落
免費加入愿碼全思維工程師社群 | 任一公眾號回復(fù)“愿碼”兩個字獲取入群二維碼
本文閱讀時長:11min
基本單元測試在我們開始討論新的概念和功能之前,讓我們來看看如何使用unittest來表達我們已經(jīng)學(xué)到的想法。這樣,我們就能有一些堅實的基礎(chǔ)來建立我們的新理解。
采取行動的時間-用unittest測試PID我們將訪問PID類(或至少訪問PID類的測試)。我們將編寫測試,以便它們在unittest框架內(nèi)運行。
我們將使用unittest框架實現(xiàn)測試。
創(chuàng)建一個名為新文件test_pid.py在同一目錄pid.py。請注意,這是一個.py文件:unittest測試是純 python源代碼,而不是包含源代碼的純文本。這意味著從紀(jì)錄片的角度來看,測試的用處不大,但可以交換其他好處。
將以下代碼插入到新創(chuàng)建的test_pid.py中
from unittest import TestCase, main from mocker import Mocker import pid class test_pid_constructor(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace("time.time") mock_time() mocker.result(1.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) mocker.restore() mocker.verify() self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 0.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 1.0) self.assertAlmostEqual(controller.previous_error, -12.0) self.assertAlmostEqual(controller.integrated_error, 0) def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=1, initial=12, when=43) self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 1.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 43.0) self.assertAlmostEqual(controller.previous_error, -11.0) self.assertAlmostEqual(controller.integrated_error, 0) class test_calculate_response(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace("time.time") mock_time() mocker.result(1.0) mock_time() mocker.result(2.0) mock_time() mocker.result(3.0) mock_time() mocker.result(4.0) mock_time() mocker.result(5.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) self.assertEqual(controller.calculate_response(6), -3) self.assertEqual(controller.calculate_response(3), -4.5) self.assertEqual(controller.calculate_response(-1.5), -0.75) self.assertEqual(controller.calculate_response(?2.25), ?1.125) mocker.restore() mocker.verify() def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12, when=1) self.assertEqual(controller.calculate_response(6, 2), -3) self.assertEqual(controller.calculate_response(3, 3), -4.5) self.assertEqual(controller.calculate_response(?1.5, 4), ?0.75) self.assertEqual(controller.calculate_response(?2.25, 5), ?1.125) if __name__ == "__main__": main()
鍵入以下命令運行測試:$ python test_pid.py
讓我們?yōu)g覽代碼部分,看看每個部分的作用。
from unittest import TestCase, main from mocker import Mocker import pid class test_pid_constructor(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace("time.time") mock_time() mocker.result(1.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) mocker.restore() mocker.verify() self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 0.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 1.0) self.assertAlmostEqual(controller.previous_error, -12.0) self.assertAlmostEqual(controller.integrated_error, 0)
在一些設(shè)置代碼之后,我們進行了測試,當(dāng)沒有給出when參數(shù)時,PID控制器正常工作。Mocker用于將time.time替換為始終返回可預(yù)測值的模擬,然后我們使用多個斷言來確認(rèn)控制器的屬性已初始化為預(yù)期值。
def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=1, initial=12, when=43) self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 1.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 43.0) self.assertAlmostEqual(controller.previous_error, -11.0) self.assertAlmostEqual(controller.integrated_error, 0)
此測試確認(rèn)在提供when參數(shù)時PID構(gòu)造函數(shù)正常工作。與之前的測試不同,不需要使用Mocker,因為測試的結(jié)果不應(yīng)該依賴于除參數(shù)值之外的任何東西 - 當(dāng)前時間是無關(guān)緊要的。
class test_calculate_response(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace("time.time") mock_time() mocker.result(1.0) mock_time() mocker.result(2.0) mock_time() mocker.result(3.0) mock_time() mocker.result(4.0) mock_time() mocker.result(5.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) self.assertEqual(controller.calculate_response(6), -3) self.assertEqual(controller.calculate_response(3), -4.5) self.assertEqual(controller.calculate_response(-1.5), -0.75) sel+f.assertEqual(controller.calculate_response(?2.25), ?1.125) mocker.restore() mocker.verify()
此類中的測試描述了calculate_response方法的預(yù)期行為。第一個測試檢查未提供可選的when參數(shù)時的行為,并模擬time.time以使該行為可預(yù)測。
def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12, when=1) self.assertEqual(controller.calculate_response(6, 2), -3) self.assertEqual(controller.calculate_response(3, 3), -4.5) self.assertEqual(controller.calculate_response(?1.5, 4), ?0.75) self.assertEqual(controller.calculate_response(?2.25, 5), ?1.125)
在此測試中,提供了when參數(shù),因此無需模擬time.time。我們只需檢查結(jié)果是否符合預(yù)期。
我們執(zhí)行的實際測試與doctest中編寫的測試相同。到目前為止,我們所看到的只是一種表達它們的不同方式。
首先要注意的是,測試文件被劃分為繼承自unittest.TestCase的類,每個類都包含一個或多個測試方法。每個測試方法的名稱以單詞test開頭,單元測試是如何識別它們是測試的。
每種測試方法都包含對單個單元的單個測試。這為我們提供了一種方便的方法來構(gòu)建我們的測試,將相關(guān)測試組合到同一個類中,以便更容易找到它們。
將每個測試放入自己的方法意味著每個測試都在一個獨立的命名空間中執(zhí)行,這使得相對于doctest風(fēng)格的測試,使得單元測試式測試更容易相互干擾。它還意味著unittest知道測試文件中有多少單元測試,而不是簡單地知道有多少表達式(您可能已經(jīng)注意到doctest將每個>>>行作為多帶帶的測試計數(shù))。最后,將每個測試放在自己的方法中意味著每個測試都有一個名稱,這可能是一個有價值的功能。
unittest中的測試并不直接關(guān)注任何不屬于調(diào)用TestCase的assert方法的任何內(nèi)容。這意味著當(dāng)我們使用Mocker時,我們不必?fù)?dān)心從演示表達式返回的模擬對象,除非我們想要使用它們。這也意味著我們需要記住寫一個斷言來描述我們想要檢查的測試的每個方面。我們將很快介紹TestCase的各種斷言方法。
如果您無法執(zhí)行測試,則測試沒有多大用處。目前,我們將采用的方式是通過Python解釋器將測試文件作為程序執(zhí)行時 調(diào)用unittest.main。這是運行unittest代碼的最簡單方法,但是當(dāng)你在很多文件中分布了大量測試時,這很麻煩。
如果__name__ =="__ main__":當(dāng) Python加載任何模塊時,它將該模塊的名稱存儲在模塊中名為__name__的變量中(除非該模塊是在命令行上傳遞給解釋器的模塊)。該模塊始終將字符串"__main__"綁定到其__name__變量。因此,如果__name__ =="__ main__":表示 - 如果此模塊直接從命令行執(zhí)行。
AssertionsAssertions是我們用來告訴unittest測試的重要結(jié)果是什么的機制。通過使用適當(dāng)?shù)臄嘌裕覀兛梢詼?zhǔn)確地告訴unittest每次測試的期望。
assertTrue當(dāng)我們調(diào)用self.assertTrue(expression)時,我們告訴unittest表達式必須為true才能使測試成功。
這是一個非常靈活的斷言,因為您可以通過編寫適當(dāng)?shù)牟紶柋磉_式來檢查幾乎任何內(nèi)容。這也是你應(yīng)該考慮使用的最后一個斷言之一,因為它沒有告訴unittest你正在進行的比較的類型,這意味著unittest無法清楚地告訴你如果測試失敗會出現(xiàn)什么問題。
有關(guān)此示例,請考慮以下測試代碼,其中包含兩個保證失敗的測試:
from unittest import TestCase, main class two_failing_tests(TestCase): def test_assertTrue(self): self.assertTrue(1 == 1 + 1) def test_assertEqual(self): self.assertEqual(1, 1 + 1) if __name__ == "__main__": main()
看起來兩個測試似乎是可以互換的,因為兩個測試都是相同的。當(dāng)然他們都會失敗(或者在不太可能的情況下,他們都會失敗),所以為什么選擇一個而不是另一個呢?
看看我們運行測試時會發(fā)生什么(并且還注意到測試沒有按照它們編寫的順序執(zhí)行;測試完全相互獨立,所以沒關(guān)系,對吧?):
你看得到差別嗎?該assertTrue測試能夠正確地確定測試失敗,但它不知道夠報告關(guān)于失敗原因的任何有用的信息。該assertEqual便測試,而另一方面,他知道首先,它是檢查兩個表達式是相等的,其次它知道如何呈現(xiàn)的結(jié)果,因此,他們將是最有用的:通過評估各個它是表達的比較并在結(jié)果之間放置一個!=符號。它告訴我們什么期望失敗,以及相關(guān)表達式評估的內(nèi)容。
assertFalse該assertFalse方法會成功時assertTrue方法會失敗,反之亦然。它在產(chǎn)生assertTrue所具有的有用輸出方面具有相同的限制,并且在能夠測試幾乎任何條件方面具有相同的靈活性。
assertEqual正如assertTrue討論中所提到的,assertEqual斷言檢查它的兩個參數(shù)實際上是相等的,并且如果它們不是,則報告失敗,以及參數(shù)的實際值。
assertNotEqual該assertNotEqual每當(dāng)斷言失敗assertEqual便斷言會成功,反之亦然。報告失敗時,其輸出表明兩個表達式的值相等,并為您提供這些值。
assertAlmostEqual正如我們之前看到的,比較浮點數(shù)可能很麻煩。特別是,檢查兩個浮點數(shù)是否相等是有問題的,因為你可能期望相等的事情 - 在數(shù)學(xué)上是相等的 - 可能仍然最終在最低有效位之間不同。浮點數(shù)僅在每個位相同時才相等。
為了解決這個問題,unittest提供了assertAlmostEqual,它檢查兩個浮點值是否幾乎相同; 它們之間的少量差異是可以容忍的。
讓我們看一下這個問題。如果取平方根7,然后將其平方,則結(jié)果應(yīng)為7.這是一對檢查該事實的測試:
from unittest import TestCase, main class floating_point_problems(TestCase): def test_assertEqual(self): self.assertEqual((7.0 ** 0.5) ** 2.0, 7.0) def test_assertAlmostEqual(self): self.assertAlmostEqual((7.0 ** 0.5) ** 2.0, 7.0) if __name__ == "__main__": main()
該test_assertEqual方法檢查
這在現(xiàn)實中是如此。然而,在計算機可用的更專業(yè)的數(shù)字系統(tǒng)中,取7的平方根然后平方它并不能讓我們回到7,所以這個測試將失敗。稍等一下。
測試test_assertAlmostEqual方法檢查
即使計算機會同意這是真的,所以這個測試應(yīng)該通過。
運行這些測試會產(chǎn)生以下結(jié)果,盡管您返回的具體數(shù)字可能會有所不同,具體取決于運行測試的計算機的詳細(xì)信息:
不幸的是,浮點數(shù)不精確,因為實數(shù)行上的大多數(shù)數(shù)字不能用有限的,非重復(fù)的數(shù)字序列表示,更不用說僅僅64位。因此,你從評估數(shù)學(xué)表達式得到的回報并不是很好。雖然 - 或者幾乎任何其他類型的工作都足夠接近政府工作 - 所以我們不希望我們的測試對這個微小的差異進行狡辯。因此,當(dāng)我們比較浮點數(shù)是否相等時,我們應(yīng)該使用assertAlmostEqual和assertNotAlmostEqual。
這個問題通常不會延續(xù)到其他比較運算符中。例如,檢查一個浮點數(shù)小于另一個,由于無意義的錯誤,不太可能產(chǎn)生錯誤的結(jié)果。只有在平等的情況下,這個問題才會困擾我們。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/43760.html
摘要:必然的,他們會拋棄標(biāo)準(zhǔn)庫中的,使用或者發(fā)明自己心儀的單元測試框架。究其原因,一些人會說時間寫代碼都不夠,哪還有空寫單元測試。最后我的個人觀點,單元測試其實還有一個非常重要的作用,就是替代函數(shù)文檔注釋。希望從今天起,你的代碼也都有單元測試。 單元測試是每種編程語言必學(xué)的課題,是保護開發(fā)者的強力護盾,每個程序員都在時間允許的情況下盡可能多的寫單元測試,今天我們不討論其必要性,只拋磚引玉聊一...
摘要:本文將進入單元測試的部分,這也是基礎(chǔ)知識中最后一個大塊。本文將重點講述和中的單元測試的生態(tài)環(huán)境。另外,在中指定要運行的單元測試用例的完整語法是。中使用模塊管理單元測試用例。每個項目的單元測試代碼結(jié)構(gòu)可 本文將進入單元測試的部分,這也是基礎(chǔ)知識中最后一個大塊。本文將重點講述Python和OpenStack中的單元測試的生態(tài)環(huán)境。 單元測試的重要性 github上有個人畫了一些不同語言的學(xué)...
摘要:所謂的單元測試,就是對一個模塊,一個函數(shù),或則是一個類進行正確性檢測的一類測試工作。當(dāng)然,單元測試也會讓代碼量大大增加。編寫單元測試代碼需要引入的包。再所有單元測試開始前運行函數(shù)在所有單元測試運行后運行。 所謂的單元測試,就是對一個模塊,一個函數(shù),或則是一個類進行正確性檢測的一類測試工作。 以測試驅(qū)動的開發(fā)方式叫做測試驅(qū)動開發(fā)(Test Drived Development). 這種開...
摘要:單元測試框架作為的標(biāo)準(zhǔn)庫,是其他單元測試框架的基礎(chǔ)。可以和和配合使用編寫單元測試。官網(wǎng)地址單元測試覆蓋率工具單元測試中還需要用到代碼覆蓋率工具。代碼覆蓋率統(tǒng)計工具用來發(fā)現(xiàn)沒有被測試覆蓋的代碼,完善單元測試的覆蓋率。 在應(yīng)用程序中,單元是具有一個或多個輸入和單個輸出的軟件中最小可測試部分。單元...
小編這這篇文章的主要目的,主要是給大家進行一個詳解,解釋一下關(guān)于Python中,單元格測試的一些具體方法,那么,測試的方法都有什么呢?下面小編就給大家詳細(xì)的做出一個解答。 一、前言 python的兩個單元測試包分別是doctest和unittest,這兩個包的使用起來各有長處,適用于不同的場景 doctest:直接寫在方法體中,利用了python動態(tài)語言的特性,書寫方式簡單明了,前提是項...
閱讀 1102·2021-11-15 18:00
閱讀 2816·2021-09-22 15:18
閱讀 1979·2021-09-04 16:45
閱讀 762·2019-08-30 15:55
閱讀 3872·2019-08-30 13:10
閱讀 1346·2019-08-30 11:06
閱讀 1994·2019-08-29 12:51
閱讀 2303·2019-08-26 13:55