2011-11-12 6 views
9

私はEXC_BAD_ACCESSの問題を解決する方法を知っていますが、その単体テスト方法はわかりません。単にクラッシュするのではなく、コードでEXC_BAD_ACCESSをキャプチャする方法はありますか?ここでEXC_BAD_ACCESSのユニットテストはどのようにして行いますか?

は私が尋ねる理由です:私はこのように、頻繁にブロックを使用してライブラリを書かれている:

doSomething:の私の実装では
- (void)doSomething:(void (^)())myBlock; 

私はこのように、最終的にブロックを実行するつもりです:

myBlock(); 

呼び出し側は、それがEXC_BAD_ACCESSでクラッシュします、ブロックにnilを渡し、その解決策は次のように、ブロックが存在することを確認する場合:

if (myBlock) { 
    myBlock(); 
} 

このnilチェックはかなり忘れやすいので、クラッシュが発生したときに失敗する単体テストを書く方法をお勧めします。クラッシュはテスト失敗と見なすことができると思いますが、クラッシュではなく素晴らしい失敗メッセージを表示するためにテストを実行しようとしている人にとっては、より良いと思います。何か案は?これは、実行を継続方法の前に満たされなければならない前提条件を強制

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

答えて

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

ええ、ええ、iOS上で 'fork()'が利用できるのかどうか分かりません。これを完全に正しく機能させるのが難しいです。私が何かを明らかにするなら、私は更新します。 –

1

私は、だからあなたのような何かができるAssertions and Logging Programming Guide

で見つかったアサーションマクロのいずれかを使用してお勧めします。また、アプリをクラッシュさせることができ、EXEC_BAD_ACCESS以外の理由が表示されます。

+1

これは単体テストではあまり役に立ちません。 greenisusには、if(myBlock){myBlock()};が含まれていて、質問に記載されていることを確認できます。問題は、私が完全に誤解していない限り、テスト中のコードのブロックをチェックするために_forgetting_をキャッチする単体テストを書く方法です。 –

+0

ジョシュは正しいです。私はそのアサーションをうまく使うことができますが、実際にテストしようとしているのは、myBlockがnilであるかどうかは関係ありませんので、メソッドをnilブロックに渡すとクラッシュしないということです。 – greenisus

+0

アサーションを使うことによって、 'myBlock'がnilでないことを保証します。単体テストでそのメソッドをテストする場合は、アサーションが失敗したためにテストが失敗します。 –

関連する問題