2011-11-12 182 views
9

我知道如何解決EXC_BAD_ACCESS問題,但我不確定如何進行單元測試。有沒有辦法在代碼中捕獲EXC_BAD_ACCESS而不是簡單地崩潰?如何爲EXC_BAD_ACCESS進行單元測試?

這就是爲什麼我問:我寫了大量使用塊庫,就像這樣:

- (void)doSomething:(void (^)())myBlock; 

我在執行的doSomething:我將最終運行塊,像這樣:

myBlock(); 

如果調用者傳遞零的塊,則它會與EXC_BAD_ACCESS崩潰,因此該解決方案是檢查在塊中存在,像這樣:

if (myBlock) { 
    myBlock(); 
} 

這個零檢查很容易忘記,所以我想寫一個單元測試失敗時發生崩潰的方法。我認爲崩潰可能被認爲是測試失敗,但我認爲對於其他人試圖運行測試來看到一個很好的失敗消息而不是崩潰的消息會更好。有任何想法嗎?

回答

4

我認爲你需要在子過程中運行測試;那麼你可以讓子進程崩潰,檢查那個崩潰,並且如果發生錯誤,測試就會失敗。

Peter Hosey's singleton test code工作。

- (void) runTestInSubprocess:(SEL)testCmd { 
     pid_t pid = fork(); 
     // The return value of fork is 0 in the child process, and it is 
     // the id of the child process in the parent process. 
     if (pid == 0) { 
      // Child process: run test 
      // isInSubprocess is an ivar of your test case class 
      isInSubprocess = YES; 
      [self performSelector:testCmd]; 
      exit(0); 
     } else { 
      // Parent process: wait for child process to end, check 
      // its status 
      int status; 
      waitpid(pid, &status, /*options*/ 0); 
      // This was a crash; fail the test 
      STAssertFalse(WIFSIGNALED(status), @"Test %@ crashed due to signal %d", NSStringFromSelector(testCmd), WTERMSIG(status)); 
     } 
} 

每個測試都那麼像這樣運行本身在一個子:

- (void) testSomething { 
    if (!isInSubprocess) { 
      // Hand off this test's selector to be run in a subprocess 
      [self runTestInSubprocess:_cmd]; 
      return; 
    } 

    // Put actual test code here 
    STAssertEquals(1, 1, @"Something wrong with the universe."); 

} 

您可能需要調整這一點;我沒有測試過它。

+0

這非常有趣。在第一次嘗試時,無論我做什麼,結果都會失敗,但該項目的目標是作爲Cocoa Touch靜態庫,並運行測試來啓動iPhone Simulator。我不認爲fork()會在那裏工作,所以我會試着將它當做Mac/Cocoa目標來看看會發生什麼。謝謝! – greenisus

+0

噢,是的,我不知道'fork()'是否可以在iOS上使用,對不起。我很難讓這個工作完全正確,如果我想出任何東西,我會更新。 –

1

我會建議使用在Assertions and Logging Programming Guide

發現所以,你可以做類似的斷言宏之一:

NSAssert(myBlock != nil, @"myBlock must not be nil") 

這種強制必須在方法之前繼續執行必須滿足的先決條件。它也允許應用程序崩潰,並會給你一個除EXEC_BAD_ACCESS之外的原因。

+1

這對單元測試沒有幫助; greenisus同樣可以包含'if(myBlock){myBlock()};'檢查他在問題中提到的內容。除非我完全誤解了這個問題,否則這個問題是如何編寫一個單元測試,它可以檢測_forgetting_來檢查被測代碼中的代碼塊。 –

+0

喬希是對的。我可以很好地使用這個斷言,但是我真正想要測試的是,當我將它們傳遞給一個零塊時,我的方法不會崩潰,所以myBlock是否爲零並不重要。 – greenisus

+0

通過使用斷言,你保證'myBlock'不是零。如果您要使用單元測試來測試該方法,則由於斷言失敗,測試將失敗。 –