2009-07-09 35 views
10

Tôi hiện đang cố gắng tìm hiểu mục tiêu-c bằng cách sử dụng XCode 3.1. Tôi đã làm việc trên một chương trình nhỏ và quyết định thêm thử nghiệm đơn vị vào nó.Tại sao kiểm tra OCUnit của tôi không thành công với "mã 138"?

Tôi đã làm theo các bước trên trang Nhà phát triển Apple - Automated Unit Testing with Xcode 3 and Objective-C. Khi tôi thêm bài kiểm tra đầu tiên của tôi, nó đã làm việc tốt khi các bài kiểm tra thất bại, nhưng khi tôi sửa chữa các bài kiểm tra xây dựng không thành công. Xcode đã báo cáo lỗi sau:

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

Cố gắng cách ly lỗi của mình, tôi đã làm theo các bước từ ví dụ Kiểm tra đơn vị ở trên và ví dụ đã làm việc. Khi tôi thêm một phiên bản đơn giản của mã của tôi và một trường hợp kiểm tra, lỗi được trả lại.

Đây là mã tôi đã tạo:

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 Tôi đã nhận lỗi cùng đăng nhập một BOOL dưới dạng chuỗi trong thử nghiệm của tôi: BOOL b = CÓ; NSLog (@ "% @", b); Lưu ý rằng nếu b = NO, nó không sụp đổ! – Rob

Trả lời

15

Tôi đã gặp phải điều này nhiều lần bản thân mình, và nó luôn luôn gây phiền nhiễu. Về cơ bản, điều này thường có nghĩa là kiểm tra đơn vị của bạn đã xảy ra sự cố nhưng không giúp cô lập lỗi. Nếu các bài kiểm tra đơn vị tạo ra kết quả đầu ra trước khi gặp lỗi (mở Build> Build Results), bạn thường có thể biết được thử nghiệm nào đang chạy khi vấn đề xảy ra, nhưng điều này một mình thường không quá hữu ích.

Đề xuất chung tốt nhất để theo dõi nguyên nhân là để gỡ lỗi các bài kiểm tra đơn vị của bạn. Khi sử dụng OCUnit, điều này không may phức tạp hơn việc chọn Run> Debug. Tuy nhiên, hướng dẫn tương tự bạn đang sử dụng có phần gần phía dưới có tiêu đề "Sử dụng Trình gỡ lỗi với OCUnit", giải thích cách tạo tệp thực thi tùy chỉnh trong Xcode để thực thi các bài kiểm tra đơn vị của bạn theo cách mà trình gỡ lỗi có thể đính kèm. Khi bạn làm như vậy, trình gỡ lỗi sẽ dừng lại ở nơi xảy ra lỗi, thay vì nhận được mã "mã 138 bí ẩn" khi mọi thứ biến mất trong ngọn lửa.

Mặc dù tôi không thể đoán chính xác những gì gây ra lỗi, tôi có một vài gợi ý ...

  • không bao giờ autorelease self trong một phương thức init - vi phạm bộ nhớ phát hành giữ lại- quy tắc. Điều đó một mình sẽ dẫn đến sự cố nếu đối tượng được phát hành bất ngờ. Ví dụ: trong phương thức testInitByIndex của bạn, testCard quay lại tự động phát hành - do đó, [testCard release] trên dòng cuối cùng == đảm bảo sự cố.
  • Tôi muốn đề nghị đổi tên phương pháp initByIndex: của bạn để initWithIndex:, hoặc thậm chí chuyển sang initWithSuit:(int)suit rank:(int)rank để bạn có thể vượt qua cả hai giá trị, thay vì một đơn int (hoặc một NSUInteger, trong đó sẽ loại bỏ thử nghiệm cho < 0) mà bạn có để xử lý.
  • Nếu bạn thực sự muốn có phương thức trả về đối tượng được tự động phát hành, bạn cũng có thể tạo phương thức tiện lợi như +(Card*)cardWithSuit:(int)suit rank:(int)rank thay thế. Phương thức này sẽ trả về kết quả của một kết hợp phân bổ một dòng/init/autorelease.
  • (Nhỏ) Khi bạn đã hoàn tất gỡ lỗi, hãy loại bỏ số dealloc mà chỉ cần gọi đến siêu. Nếu bạn đang cố gắng tìm bộ nhớ không bao giờ bị phân phối, thì việc tìm kiếm bằng dụng cụ cũng dễ dàng hơn nhiều.
  • (Niggle) Đối với phương pháp thử của bạn, hãy cân nhắc sử dụng STAssetEquals(testCard.rank, 0, ...) để thay thế. Nó kiểm tra cùng một điều, nhưng bất kỳ lỗi kết quả nào cũng dễ hiểu hơn một chút.
  • (tầm thường) Bạn không phải khai báo phương pháp thử đơn vị trong @interface. OCUnit tự động chạy bất kỳ phương thức nào có định dạng -(void)test... cho bạn. Nó không làm tổn thương để tuyên bố chúng, nhưng bạn sẽ tiết kiệm cho mình một số đánh máy nếu bạn chỉ cần bỏ qua chúng. Trên một lưu ý liên quan, tôi thường chỉ có một tập tin .m cho các bài kiểm tra đơn vị, và đặt phần @interface ở đầu tập tin đó. Điều này làm việc tuyệt vời vì không ai khác cần phải bao gồm giao diện thử nghiệm đơn vị của tôi.
  • (Đơn giản) Trừ khi bạn phân lớp CardTestCases, đơn giản hơn là chỉ cần loại bỏ tệp .h và đặt @interface ở đầu tệp .m thay thế. Các tệp tiêu đề là cần thiết khi nhiều tệp cần bao gồm các khai báo, nhưng điều này thường không phải là trường hợp với các bài kiểm tra đơn vị.

Dưới đây là những gì các tập tin thử nghiệm có thể trông giống như với các đề xuất này:

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 là thủ phạm. Tôi nhớ gõ tên tập tin để viết câu hỏi nên mẹo 4 không phải là vấn đề. mẹo 2 - mã của tôi chứa các hàm init khác bao gồm cả hàm được đề xuất. Tôi muốn giới hạn mã của mình càng nhiều càng tốt trong một nỗ lực để cô lập lỗi. – Joe

+0

Rất vui được giúp đỡ. Đã xóa mẹo đặt tên tệp vì đó là lỗi đánh máy. Bạn thông minh đã chỉ đăng mã gây ra lỗi. :-) –

Các vấn đề liên quan