2014-01-10 26 views
38

每默認模板中的註釋爲XCTestCase關於setUpXCTestCase的setUp方法的目的是什麼?

Put setup code here; it will be run once, before the first test case.

然而,在XCTestCase.h,上述setUp狀態不同的意見:

Setup method called before the invocation of each test method in the class.

要確認的實際行爲,我把NSLog放在setUp之內來計算它被調用的次數:

static int count = 0; 

- (void)setUp 
{ 
    [super setUp]; 
    count++; 

    NSLog(@"Call Count = %d", count); 
} 

這導致setUp方法每個測試方法(確認上XCTestCase.h註釋)之前被調用。

我想用setUp方法來創建測試/模擬對象一次(例如設置一個核心數據測試棧)。一遍又一遍地創建這些將會是處理器密集型的,並且可能非常緩慢。

所以,

1)什麼是setUp實際上打算用來做什麼?開發人員不是一遍又一遍地創建對象嗎?

2)我怎樣才能創建這些對象只有一次XCTestCase內?

回答

86

這裏有幾點需要討論:setUp方法的行爲和一般最佳測試實踐。

實際上有 setUp方法:

+ (void)setUp; 
- (void)setUp; 

類方法(+ (void)setUp)僅在整個測試運行期間運行一次。

實例方法(- (void)setUp)是默認模板中的實例方法;它在每次測試之前運行。希望在假設的未來版本的Xcode中,此評論將被更改爲​​WINK WINK

所以通過這兩種方法,您描述的兩種行爲都是可能的。

關於你的評論:「當然開發商沒有遍地創造它的對象」

我的答案是「是的,他們通常是」。對於 '好' 的單元測試的一個流行的縮寫,是第一:

  • 快速
  • 隔離
  • 重複
  • 自我驗證
  • 及時

隔離的關鍵是這個討論:你的測試不應該依賴於其他測試留下的任何以前的狀態。理想情況下,您應該拆除並重新創建您的內存核心數據堆棧,以便進行每項測試,這樣您就知道自己是從乾淨的石板開始的。一個很好的例子是this post by Graham Lee。你想使用內存棧,因爲a)你可以很容易地把它扔掉,b)它應該非常快,因爲它只是在內存中而不是你的磁盤。

如果你發現你的試驗以這樣的結果運行速度慢的(不要過早優化),那麼我認爲一個合理的下一個步驟是創建在+ (void)setUp方法堆棧,但創建品牌每次在你的- (void)setUp方法中新的上下文。

+2

+1:很好的回答!是的,考慮它,* 1)測試順序不能保證*(但是有很好的測試,不管什麼時候會發生什麼都沒有關係)和* 2)測試不應該受到其他測試的影響*你提到,他們'不應該依賴任何以前的測試狀態')。 「內存」堆棧也是個好主意。這正是我要做的。 –

+0

看完這個答案之後,我立即刪除了我的+1;)注意:XCTest或多或少是SenTest的副本,它繼承了它的所有限制。有更好的測試框架可以任意嵌套,其中_setup_和_teardown_過程是顯而易見的。不幸的是,Xcode和XCTest遠遠落後,將非常酷的第三方測試框架集成到令人興奮的Xcode測試框架中非常困難。 – CouchDeveloper

+0

@ JRG-Developer完全正確 - 測試訂單不能保證。 @CouchDeveloper例如,[specta](https://github.com/specta/specta)有'beforeEach','beforeAll','afterEach'和'afterAll'方法。 –

3

我來到這裏幾乎相同的問題:如何執行setUp只有一次,並在Swift。這裏是解決方案:

override class func setUp() { 
    super.setUp()  
    // ... 
} 

override class func tearDown() {  
    // ... 
    super.tearDown() 
} 

現在我還在尋找一個解決方案爲異步setUp

+4

異步setUp似乎沒有用處,因爲根據定義,您希望在您運行該類中的任何測試之前完成setUp。 –

相關問題