2009-07-09 113 views
10

我目前正在嘗試使用XCode 3.1來學習objective-c。我一直在研究一個小程序,並決定添加單元測試。爲什麼我的OCUnit測試失敗,顯示「code 138」?

我遵循Apple Developer頁面上的步驟 - Automated Unit Testing with Xcode 3 and Objective-C。當我添加我的第一個測試時,測試失敗時工作正常,但是當我更正測試時,構建失敗。 Xcode中報告了以下錯誤:

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

試圖孤立我的錯誤,我再接着從上面的單元測試示例中的步驟和例子工作。當我添加我的代碼和測試用例的簡化版本時,返回錯誤。

這裏是我創建的代碼:

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

僅供參考,我得到了同樣的錯誤記錄布爾在我的測試字符串: BOOL b = YES; NSLog(@「%@」,b);請注意,如果b = NO,它不會崩潰! – Rob 2011-06-08 06:20:35

回答

15

我遇到了這個無數次自己,它總是煩人。基本上,這通常意味着您的單元測試確實發生了崩潰,但無法隔離錯誤。如果單元測試在崩潰之前產生輸出(打開Build> Build Results),通常您至少可以瞭解發生問題時測試的運行情況,但這通常不會有幫助。

追查原因的最佳一般建議是調試您的單元測試。當使用OCUnit時,不幸的是比選擇Run> Debug更復雜。不過,您正在使用的相同教程的底部標題爲「使用調試器與OCUnit」,它解釋瞭如何在Xcode中創建自定義可執行文件,以便調試器可以附加到的方式執行單元測試。當你這樣做的時候,調試器會停止發生錯誤的地方,而不是在所有事情都在火焰中時發出神祕的「代碼138」。

雖然我可能無法猜測究竟是什麼導致的,我確實有一些建議...

  • 永遠,永遠在init方法自動釋放self錯誤 - 它違反保留釋放內存規則。如果對象被意外釋放,那就會導致崩潰。例如,在您的testInitByIndex方法中,testCard會自動返回 - 因此,[testCard release]最後一行==保證崩潰。
  • 我建議重新命名initByIndex:方法initWithIndex:,甚至切換到initWithSuit:(int)suit rank:(int)rank這樣你就可以通過這兩個值,而不是單個int(或NSUInteger,這將消除< 0測試),你必須處理。
  • 如果你確實想要一個返回自動釋放對象的方法,你也可以創建一個方便的方法,如+(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 - 我的代碼包含其他初始化函數,包括建議的函數。我想盡可能限制我的代碼以嘗試隔離錯誤。 – Joe 2009-07-11 14:22:42

相關問題