2013-05-05 37 views
1

後主動意見的方式,並推斷出了它是如何工作的,我仍然認爲:Specs2打破我的測試數據,由於它與迭代工作

將是很好,不過,如果specs2提供非消耗品邏輯,沿 與迭代器消費品。就像如果我不使用iterator.size方法直接, 但使用規範的方法,如:haveSize

我有一個測試,其中有一個代碼:

val ids = for(software <- parser) yield software.productID 

//ids.size must_== 2; 

ids.foreach(x => println(x)) 

它產生輸出:

1 
2 

如果我去掉SPEC2校驗(ids.size must_== 2),它將帶有空輸出提供。

似乎spec2,遍歷迭代器(ids),然後我最終與指向數據結束(空迭代器)的迭代器。因此我不能再使用這個迭代器 - 在接下來的測試中。

請問spec2 /測試框架的行爲如何?

所以,如果我用這樣的測試(由於某種原因):

ids.size must_== 2; 
    ids.size must_== 2; 

它會失敗。

// -

這裏我們使用迭代器的size()方法。所以,我有這個沒關係有這樣的行爲。但是,如果使用這樣的代碼:

Ids.toIterable must haveSize(2); // here we do not use iterator.size() method dirrectly 
for(id <- ids) println(id). 

什麼都不打印。 看來它仍然會消耗我的「差」的迭代器..


found一個變通辦法:

val (it1, it2) = ids.duplicate  

    it1.size must_== 2; 
    it2.size must_== 2; 

而與此(轉換爲單),它也將使用(就像是在意見建議):

val ids = for(software <- parser.toList) yield software.productID 

但這正是SPEC2可以在默認情況下(使用方法,如haveSize)。 (我發佈了一個bug)。

+1

爲什麼不將迭代器轉換爲列表? – Antimony 2013-05-05 01:38:26

+0

這是我想出的第一個解決方案。只是沒有想到,並想知道爲什麼測試顯示我是真實的,但數據是空的 – ses 2013-05-05 01:45:46

+0

可能是合乎邏輯的spec2用戶的迭代器複製,但不是原來的 – ses 2013-05-05 01:51:40

回答

2

當您編寫iterator.size must_== 2時,您會消耗自己的迭代器,specs2只會收到值2(如果迭代器的大小爲2)。所以沒有什麼規格2可以做到這一點。

然後,您可以通過編寫iterator must haveSize(2)來要求specs2檢查迭代器大小,並期望迭代器不被使用。我不認爲這也是一個好主意。我認爲iterator must haveSize(2)可以合理地作爲iterator.size must be_==(2)的簡寫,它會消耗迭代器。

我的建議是留給用戶代碼控制是否應該消耗或不消耗的決定。您可以留下您的迭代器,因爲它是,或者如果你想既評估其規模檢查它的元素把它轉化爲一個Stream

val iterator = Seq({println(1); 1}, {println(2); 2}).iterator 
val elements = iterator.toStream 

elements must haveSize(2) 
elements(1) === 2 
+0

明白了。我沒有想到size()是迭代器的方法。我認爲這是spec2的方法在頂部/與itarator相關。 – ses 2013-05-05 18:21:52

+0

Ids.toIterable必須具有Size(2); for(id < - ids)println(id)。什麼都不打印。它似乎仍然消耗我的'窮人'迭代器.. – ses 2013-05-05 18:43:47

+0

雖然,如果specs2提供非消耗性邏輯以及消耗品,那將會很不錯。就像如果我不直接使用iterator.size方法,但使用specs的方法如:hasSize – ses 2013-05-05 19:06:11

0

迭代器是可變的,並且只能使用一次消耗,在這種情況下通過調用.size。 scaladoc提供了有用的細節,並提到「在調用方法之後,永遠不要使用迭代器」。

你似乎需要的是一個集合,它是Iterable的子類型(它包含一個foreach方法),如List或Vector。如果你只是像在這個例子中那樣調用foreach,你所需要做的就是用{..}在第一行中圍繞for循環,然後添加.toIterable或toList,否則下面的代碼會起作用。

val ids = parser.map(_.software).toIterable // collection would be the same as parser 
ids.size must_== 2; 
ids.size must_== 2;