2009-07-09 14 views
10

私は現在、XCode 3.1を使ってobjective-cを学習しようとしています。私は小さなプログラムに取り組んできており、単体テストを追加することに決めました。「コード138」でOCUnitテストが失敗するのはなぜですか?

私は、Apple Developerページの手順 - Automated Unit Testing with Xcode 3 and Objective-Cに従っています。最初のテストを追加したときに、テストが失敗したときに正常に機能しましたが、テストを修正するとビルドに失敗しました。

error: Test host '/Users/joe/Desktop/OCT/build/Debug/OCT.app/Contents/MacOS/OCT' exited abnormally with code 138 (it may have crashed).

は私のエラーを分離しようとすると、Iユニットテストの例から再続く上記の手順と例が働い:Xcodeは、次のエラーを報告しました。コードとテストケースの単純化バージョンを追加すると、エラーが返されました。

Card.h

#import <Cocoa/Cocoa.h> 
#import "CardConstants.h" 

@interface Card : NSObject { 
    int rank; 
    int suit; 
    BOOL wild ; 
} 

@property int rank; 
@property int suit; 
@property BOOL wild; 

- (id) initByIndex:(int) i; 

@end 

Card.m

#import "Card.h" 

@implementation Card 

@synthesize rank; 
@synthesize suit; 
@synthesize wild; 

- (id) init { 
    if (self = [super init]) { 
     rank = JOKER; 
     suit = JOKER; 
     wild = false; 
    } 
    return [self autorelease]; 
} 

- (id) initByIndex:(int) i { 
    if (self = [super init]) { 
     if (i > 51 || i < 0) { 
      rank = suit = JOKER; 
     } else { 
      rank = i % 13; 
      suit = i/13; 
     } 
     wild = false; 
    } 
    return [self autorelease]; 
} 

- (void) dealloc { 
    NSLog(@"Deallocing card"); 
    [super dealloc]; 
} 

@end 

CardTestCases.h

:ここ

は、私が作成したコードです

#import <SenTestingKit/SenTestingKit.h> 

@interface CardTestCases : SenTestCase { 
} 
- (void) testInitByIndex; 
@end 

CardTestCases.m

#import "CardTestCases.h" 
#import "Card.h" 

@implementation CardTestCases 

- (void) testInitByIndex { 
    Card *testCard = [[Card alloc] initByIndex:13]; 
    STAssertNotNil(testCard, @"Card not created successfully"); 
    STAssertTrue(testCard.rank == 0, 
       @"Expected Rank:%d Created Rank:%d", 0, testCard.rank); 
    [testCard release]; 
} 
@end 
+0

FYI私は私のテストでは、文字列としてBOOLをログに同じエラーを得ました: BOOL b = YES; NSLog(@ "%@"、b); b = NOの場合、クラッシュしないことに注意してください。 – Rob

答えて

15

私はこの何度も自分自身に遭遇してきた、そしてそれは常に迷惑なんです。基本的には、通常、ユニットテストは、でクラッシュしましたが、エラーを特定するのには役立ちません。ユニットがクラッシュする前に出力を生成した場合(ビルド>ビルド結果を開く)、通常は問題が発生したときにどのテストが実行されているかを知ることができます。

原因を突き止めるための最も一般的な提案は、ののデバッグです。 OCUnitを使用する場合、これは残念ながら実行>デバッグを選択するより複雑です。しかし、使用しているチュートリアルの下には、「OCUnitでデバッガを使用する」というセクションがあります。これは、デバッガが接続できるようにユニットテストを実行するためのカスタム実行可能ファイルをXcodeに作成する方法を説明しています。そうすると、デバッガは、すべてが不調になったときに不思議な「コード138」を取得するのではなく、エラーが発生した場所で停止します。

私は、エラーを引き起こしている正確に何を推測することはできないかもしれないが、私はいくつかの提案を持っている...

  • は、EVER initメソッドでselfを自動解放決して - それは保持解除をメモリに違反ルールオブジェクトが予期せずに解放された場合、それだけでクラッシュする可能性があります。たとえば、testInitByIndexの方法ではtestCardが自動返却されます。したがって、最後の行には[testCard release] ==保証付きクラッシュが発生します。
  • 私はあなたが処理する必要があること(< 0のテストを排除することになる、またはNSUInteger)の代わりに、単一のintの、両方の値を渡すことができinitWithIndex:にごinitByIndex:方法の名前を変更する、あるいはinitWithSuit:(int)suit rank:(int)rankへの切り替えをお勧めしたいです。
  • 実際にには、自動解放されたオブジェクトを返すメソッドが必要な場合は、+(Card*)cardWithSuit:(int)suit rank:(int)rankのような簡易メソッドを作成することもできます。このメソッドは、単一行のalloc/init/autoreleaseの組み合わせの結果を返します。
  • (マイナー)デバッグが終了したら、superを呼び出すだけのdeallocを取り除いてください。とにかく割り振り解除されていないメモリを見つけようとしているのであれば、Instrumentsを使って見つけるのはずっと簡単です。
  • (Niggle)テスト方法には、代わりにSTAssetEquals(testCard.rank, 0, ...)を使用することを検討してください。それは同じことをテストしますが、結果として生じるエラーは理解しやすくなります。
  • (簡体字)@interfaceに単体テスト方法を宣言する必要はありません。 OCUnitは、フォーマット-(void)test...の任意のメソッドを動的に実行します。それを宣言するのは害ではありませんが、あなたがそれらを省略すると、あなたは入力を省くことができます。関連するノートでは、私は通常単体テスト用の.mファイルしか持っていないので、そのファイルの先頭に@interfaceセクションを置いています。誰も私の単体テストインタフェースを含める必要がないので、これは素晴らしいことです。
  • (簡素化)CardTestCasesをサブクラス化しない限り、単に.hファイルを削除し、@interfaceを.mファイルの先頭に置く方が簡単です。ヘッダファイルは、複数のファイルに宣言を含める必要がある場合に必要ですが、通常は単体テストではありません。ここで

は、テストファイルはこれらの提案をどのように見えるかです:

CardTest.m

#import <SenTestingKit/SenTestingKit.h> 
#import "Card.h" 

@interface CardTest : SenTestCase 
@end 

@implementation CardTest 

- (void) testInitWithIndex { 
    Card *testCard = [[Card alloc] initWithIndex:13]; 
    STAssertNotNil(testCard, @"Card not created successfully"); 
    STAssertEquals(testCard.rank, 0, @"Unexpected card rank"); 
    [testCard release]; 
} 
@end 
+0

autoreleaseが原因でした。私は質問を書いてファイル名をタイプミスしたので、ヒント4は問題ではなかった。ヒント2 - 私のコードには、提案されたものを含む他のinit関数が含まれています。エラーを分離するためにできるだけコードを制限したいと思っていました。 – Joe

+0

助けてくれてうれしいです。ファイル名のヒントが誤字であったので削除しました。エラーの原因となったコードだけを投稿した方が賢明です。 :-) –

関連する問題