自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

在Jupyter notebooks中進行單元測試

開發(fā) 測試
我們都知道開發(fā)過程中應(yīng)該編寫單元測試,實際上我們中的許多人都這樣做。對于生產(chǎn)代碼,庫代碼,或者歸因于測試驅(qū)動的開發(fā)過程,這一點尤其正確。

[[389287]]

我們都知道開發(fā)過程中應(yīng)該編寫單元測試,實際上我們中的許多人都這樣做。對于生產(chǎn)代碼,庫代碼,或者歸因于測試驅(qū)動的開發(fā)過程,這一點尤其正確。

通常,Jupyter notebooks用于數(shù)據(jù)探究,因此用戶可能不選擇(或不需要)為其代碼編寫單元測試,因為當(dāng)他們在Jupyter中運行時,通常會查看每個單元格的結(jié)果,然后得出結(jié)論,之后繼續(xù)。但是,以我的經(jīng)驗來看,Jupyter通常會發(fā)生的情況是,Jupyter中的代碼很快就超出了數(shù)據(jù)探究的范圍,對于進一步的工作很有用。或者,Jupyter本身可能會產(chǎn)生有用的結(jié)果,需要定期運行。也許需要維護代碼并將其與外部數(shù)據(jù)源集成。然后,確??梢詼y試和驗證notebook中的代碼就變得很重要。

在這種情況下,我們有哪些選擇對Jupyter代碼來進行單元測試?在本文中,我將介紹在Jupyter notebooks中對Python代碼進行單元測試的幾個選項。

也許只是不做?

Jupyter notebook 單元測試的第一個選擇是根本不做。這樣,我并不是說不要對代碼進行單元測試,而是將其從notebook 中提取到單獨的Python模塊中,然后再將其重新導(dǎo)入notebook 中。應(yīng)該使用通常對單元代碼進行單元測試的方式來測試該代碼,無論是使用unittest,pytest,doctest還是其他單元測試框架。本文不會詳細介紹所有這些框架,但是對于python開發(fā)人員來說,一個不錯的選擇是不在其Jupyter notebook本中進行測試,而是使用多種可用于Python代碼的測試框架,并在開發(fā)過程中盡快將代碼移至外部模塊。

在notebook中進行測試

如果最終決定要將代碼保留在Jupyter notebook中,則實際上有一些單元測試選項。在復(fù)習(xí)其中的一些內(nèi)容之前,讓我們先設(shè)置一個在Jupyter notebook中可能會遇到的代碼示例。假設(shè)您的notebook從API中提取了一些數(shù)據(jù),從中計算出一些結(jié)果,然后生成了一些圖表和其他數(shù)據(jù)摘要,這些摘要會一直保存在其他地方。也許有一個函數(shù)可以產(chǎn)生正確的API URL,我們想對該函數(shù)進行單元測試。此功能具有一些邏輯,可以根據(jù)報告的日期更改URL格式。這是經(jīng)過調(diào)試的版本。 

  1. import datetime  
  2. import dateutil  
  3. def make_url(date):  
  4.     """Return the url for our API call based on date."""  
  5.     if isinstance(date, str):  
  6.         date = dateutil.parser.parse(date).date()  
  7.     elif not isinstance(date, datetime.date):  
  8.         raise ValueError("must be a date")  
  9.     if date >= datetime.date(2020, 1, 1): 
  10.         return f"https://api.example.com/v2/{date.year}/{date.month}/{date.day}"  
  11.     else:  
  12.         return f"https://api.example.com/v1/{date:%Y-%m-%d}" 

使用unittest進行單元測試

通常,當(dāng)我們使用unittest進行測試時,我們會將測試方法放在單獨的測試模塊中,或者可能將這些方法混入主模塊中。然后,我們需要執(zhí)行unittest.main方法,可能是__main__防護中的默認方法。我們基本上可以在Jupyter notebook中執(zhí)行相同的操作。我們可以創(chuàng)建一個unitest.TestCase類,執(zhí)行所需的測試,然后僅在任何單元格中執(zhí)行單元測試。您只需要保存unittest.main方法的輸出并檢查是否有錯誤。 

  1. import unittest  
  2. class TestUrl(unittest.TestCase):  
  3.     def test_make_url_v2(self):  
  4.         date = datetime.date(2020, 1, 1)  
  5.         self.assertEqual(make_url(date), "https://api.example.com/v2/2020/1/1")      
  6.      def test_make_url_v1(self):  
  7.         date = datetime.date(2019, 12, 31)  
  8.         self.assertEqual(make_url(date), "https://api.example.com/v1/2019-12-31")       
  9.  res = unittest.main(argv=[''], verbosity=3exit=False 
  10. # if we want our notebook to stop processing due to failures, we need a cell itself to fail  
  11. assert len(res.result.failures) == 0  
  1. test_make_url_v1 (__main__.TestUrl) ... ok  
  2. test_make_url_v2 (__main__.TestUrl) ... ok  
  3. ----------------------------------------------------------------------  
  4. Ran 2 tests in 0.001s  
  5. OK 

事實證明,這非常簡單,如果您不介意在notebook中混合使用代碼和進行測試,那么效果很好。

使用doctest進行單元測試

在代碼中包含測試的另一種方法是使用doctest。Doctest使用特殊格式的代碼文檔,其中包括我們的測試和預(yù)期結(jié)果。下面是包含此特殊代碼文檔的更新方法,包括正例和負例。這是一種在一個地方測試和記錄代碼的簡單方法,通常會在python模塊中使用,main頭文件將僅在其中運行doct測試,如下所示: 

  1. if __name__ == __main__:  
  2.     doctest.testmod() 

由于我們在notebook中,因此只需將其添加到定義了代碼的單元格中,它也將起作用。首先,這是我們更新的帶有doctest注釋的make_url方法。 

  1. def make_url(date):  
  2.     """Return the url for our API call based on date.  
  3.     >>> make_url("1/1/2020")  
  4.     'https://api.example.com/v2/2020/1/1'   
  5.      >>> make_url("1-1-x1")  
  6.     Traceback (most recent call last):  
  7.         ...  
  8.     dateutil.parser._parser.ParserError: Unknown string format: 1-1-x1   
  9.      >>> make_url("1/1/20001")  
  10.     Traceback (most recent call last):  
  11.         ...  
  12.     dateutil.parser._parser.ParserError: year 20001 is out of range: 1/1/20001  
  13.      >>> make_url(datetime.date(2020,1,1))  
  14.     'https://api.example.com/v2/2020/1/1'    
  15.      >>> make_url(datetime.date(2019,12,31))  
  16.     'https://api.example.com/v1/2019-12-31'  
  17.     """  
  18.     if isinstance(date, str):  
  19.         date = dateutil.parser.parse(date).date() 
  20.      elif not isinstance(date, datetime.date):  
  21.         raise ValueError("must be a date")  
  22.     if date >= datetime.date(2020, 1, 1):  
  23.         return f"https://api.example.com/v2/{date.year}/{date.month}/{date.day}"  
  24.     else:  
  25.         return f"https://api.example.com/v1/{date:%Y-%m-%d}"  
  26. import doctest  
  27. doctest.testmod()  
  1. TestResults(failed=0attempted=5

用testbook進行單元測試

testbook項目是notebook 單元測試的另一種方式。它允許您從notebook 外部以純Python代碼方式引用notebook 。這使您可以在單獨的Python模塊中使用任何您喜歡的測試框架(例如pytest或unittest)。您可能會遇到這樣的情況:允許用戶修改和更新notebook代碼是保持代碼更新并為最終用戶提供靈活性的最佳方法。但是您可能希望仍單獨對代碼進行測試和驗證。Testbook使其成為一個選項。

首先,您必須將其安裝在您的環(huán)境中:

  1. pip install testbook 

或者在你的notebook中:

  1. %pip install testbook 

現(xiàn)在,在一個單獨的python文件中,您可以導(dǎo)入notebook代碼并在那里進行測試。在該文件中,您將創(chuàng)建類似于以下代碼的代碼,然后使用您更喜歡實際執(zhí)行單元測試的任何單元測試框架。您可以在Python文件中創(chuàng)建以下代碼(例如jupyter_unit_tests.py)。 

  1. import datetime  
  2. import testbook  
  3. @testbook.testbook('./jupyter_unit_tests.ipynb', execute=True 
  4. def test_make_url(tb): 
  5.      func = tb.ref("make_url")  
  6.     date = datetime.date(2020, 1, 2)  
  7.     assert make_url(date) == "https://api.example.com/v2/2020/1/1" 

在這種情況下,您現(xiàn)在可以使用任何單元測試框架來運行測試。例如,使用pytest,您只需運行以下命令: 

  1. pytest jupyter_unit_tests.py 

這可以作為正常的單元測試,并且測試應(yīng)該通過。但是,在撰寫本文時,我意識到testbook代碼對將單元測試中的參數(shù)傳遞回notebook內(nèi)核進行測試的支持有限。這些參數(shù)是JSON序列化的,并且當(dāng)前代碼知道如何處理各種Python類型。但是,它不會將日期時間作為對象傳遞,而是作為字符串傳遞。由于我們的代碼嘗試將字符串解析為日期(在我對其進行修改之后),因此它可以工作。換句話說,上面的單元測試不是將datetime.date傳遞給make_url方法,而是傳遞一個字符串(2020-01-02),然后將其解析為一個日期。您如何將日期從單元測試傳遞到notebook代碼中?您有以下幾種選擇。首先,您可以在notebook中創(chuàng)建一個日期對象,僅用于測試目的,然后在單元測試中引用它。

  1. testdate1 = datetime.date(2020,1,1)  # for unit test 

然后,您可以編寫單元測試以在測試中使用該變量。

第二種選擇是將Python代碼寫入notebook,然后在單元測試中重新引用它。這兩個選項都顯示在外部單元測試的最終版本中。只需將其保存在jupyter_unit_tests.py上,然后使用您喜歡的單元測試框架來運行它。 

  1. import datetime  
  2. import testbook  
  3. @testbook.testbook('./jupyter_unit_tests.ipynb', execute=True 
  4. def test_make_url(tb):  
  5.     f = tb.ref("make_url")  
  6.     d = "2020-01-02"  
  7.     assert f(d) == "https://api.example.com/v2/2020/1/2"  
  8.     # note that this is actually converted to a string  
  9.     d = datetime.date(2020, 1, 2)  
  10.     assert f(d) == "https://api.example.com/v2/2020/1/2"  
  11.     # this one will be testing the date functionality  
  12.     d2 = tb.ref("testdate1")  
  13.     assert f(d2) == "https://api.example.com/v2/2020/1/1"  
  14.     # this one will inject similar code as above, then use it  
  15.     tb.inject("d3 = datetime.date(2020, 2, 3)")  
  16.     d3 = tb.ref("d3")  
  17.     assert f(d3) == "https://api.example.com/v2/2020/2/3" 

總結(jié)

因此,無論您是單元測試的純粹主義者還是只想在notebooks中添加一些單元測試,您都可以考慮以上幾種選擇。不要讓notebooks的使用妨礙您在測試代碼方面做正確的事情。 

 

責(zé)任編輯:龐桂玉 來源: Python中文社區(qū) (ID:python-china)
相關(guān)推薦

2017-01-14 23:26:17

單元測試JUnit測試

2017-01-16 12:12:29

單元測試JUnit

2013-06-04 09:49:04

Spring單元測試軟件測試

2017-03-23 16:02:10

Mock技術(shù)單元測試

2017-01-14 23:42:49

單元測試框架軟件測試

2021-03-28 23:03:50

Python程序員編碼

2009-08-19 09:00:48

單元測試框架自動化測試

2009-06-22 10:29:11

集成測試Spring

2012-11-01 11:32:23

IBMdw

2012-11-01 11:37:05

JavaScript單元測試測試工具

2023-08-02 13:59:00

GoogleTestCTest單元測試

2022-12-08 08:01:02

Python測試單元

2009-06-08 19:59:09

EclipseJUnit單元測試

2009-06-08 19:57:29

EclipseJUnit4單元測試

2009-06-08 20:04:06

EclipseJUnit4單元測試

2011-06-20 16:41:59

單元測試

2023-12-11 08:25:15

Java框架Android

2017-12-12 13:17:36

機器學(xué)習(xí)代碼單元測試

2020-08-18 08:10:02

單元測試Java

2023-07-26 08:58:45

Golang單元測試
點贊
收藏

51CTO技術(shù)棧公眾號