2010-09-24 40 views
1

我正在運行一個單元測試正在處理的使用生成器的Python項目的問題。簡化,項目/單元測試看起來像這樣:在不同單元測試中重用發生器

我有一個setUp()函數,它創建一個Person實例。 Person是一個具有生成器next_task()的類,它產生了Person所具有的下一個任務。

我現在有兩個單元測試,使用for循環測試發生器工作方式的不同事情。第一次測試完全符合我的預期,第二次測試甚至從未進入循環。在這兩個單元測試,代碼的第一行是:

for rank, task in enumerate(self.person.next_task()): 

我的猜測是,這是行不通的,因爲是在兩個獨立的單元測試所使用的相同的發電機的功能。但這似乎並不像發電機組測試應該起作用的發電機的方式。我不應該在任務列表中迭代兩次嗎?另外,因爲Person實例是在setUp()中創建的,所以不應該每個單元測試都使用一個基本上不同的Person實例?

+0

如果您自己運行第二項測試,那麼第二項測試是否可行?例如如果你在命令行中指定它。用'python testfile。py TestClass.testMethod' – 2010-09-24 16:19:41

+0

這是* iterators *的工作方式:值不存儲在列表中。一旦你遍歷了迭代器一次,你就無法重新開始並重新執行。這聽起來像兩個測試正在測試'Person'的同一個實例;你可以通過讓它們打印'id(self.person)'來檢查它。 – katrielalex 2010-09-24 16:24:36

+1

'Person.next_task()'方法是什麼樣的? 'setUp()'方法怎麼樣?從你的描述來看,這聽起來像兩個測試應該使用兩個獨立的'Person'實例,因爲你正在'setUp()'中創建它們。 – 2010-09-24 16:29:22

回答

3

如果你真的在setUp中創建一個新的Person對象,那麼它應該像你期望的那樣工作。有幾個原因可能導致它不能正常工作:

1)您正在從另一個迭代器初始化Person的任務,並且在您第二次創建Person時已耗盡。

2)您每次創建一個新的Person對象,但任務生成器是一個類變量而不是實例變量,因此在類實例之間共享。

3)你認爲你正在創建一個新的Person對象,但實際上你不是因爲某種原因。也許它是作爲一個單例實現的。

4)unittest setUp方法被破壞。

其中我認爲(4)的可能性最小,但在我們追蹤真正的問題之前,我們需要查看更多的代碼。

+0

謝謝 - 它實際上就像#2一樣。生成器實際上是指一個類變量(一組),並且我忘記了在每個單元測試結束時清除類變量。 – chimeracoder 2010-10-01 17:49:36

0

生成器的生成結果由使用它的第一個for循環消耗。之後,生成器函數返回並完成 - 因此爲空。由於第二個單元測試使用了相同的生成器對象,因此它不會進入循環。您必須爲第二個單元測試創​​建一個新的生成器,或者使用itertools.tee將N個獨立的迭代器放在一個生成器之外。

發電機不按照您的想法工作。每次調用generatorObject.next()時,都會返回下一個產生的結果,但結果不會被存儲到任何位置。這就是爲什麼發電機經常用於懶惰操作的原因。如果您想重新使用結果,您可以按照我所說的使用itertools.tee,或者將生成器轉換爲元組/結果列表。

使用itertools.tee從文檔一個提示:

這itertool可能需要顯著輔助存儲(取決於如何需要存儲多臨時數據)。通常,如果一個迭代器在另一個迭代器啓動之前使用大部分或全部數據,則使用list()而不是tee()會更快。