2009-07-09 5 views
10

В настоящее время я пытаюсь изучить цель-c с помощью XCode 3.1. Я работал над небольшой программой и решил добавить к ней модульное тестирование.Почему мои тесты OCUnit терпят неудачу с «кодом 138»?

Я выполнил шаги на странице разработчиков Apple - 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

FYI Я получил ту же ошибку при входе в BOOL в виде строки в моем тесте: BOOL b = ДА; NSLog (@ "% @", b); Обратите внимание, что если b = NO, это не сбой! – Rob

ответ

15

Я столкнулся с этим много раз себя, и это всегда раздражает. В основном, это обычно означает, что ваш блок тесты сделал аварии, но не помогает изолировать ошибку. Если тесты модуля выдают результат перед сбоем (open Build> Build Results), вы обычно можете получить представление о том, какой тест выполнялся при возникновении проблемы, но это само по себе не слишком полезно.

Лучшее общее предложение для отслеживания причины: отладить модульные тесты. При использовании OCUnit это, к сожалению, сложнее, чем выбор Run> Debug. Тем не менее, в том же учебнике, который вы используете, есть раздел под названием «Использование отладчика с OCUnit», в котором объясняется, как создать пользовательский исполняемый файл в Xcode для выполнения ваших модульных тестов таким образом, чтобы отладчик мог подключиться. Когда вы это сделаете, отладчик остановится там, где произошла ошибка, вместо того, чтобы получить таинственный «код 138», когда все сгорело в огне.

Хотя я не могу быть в состоянии догадаться, что именно это вызывает ошибку, у меня есть несколько предложений ... не

  • НИКОГДА, НИКОГДА autorelease 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.
  • (Незначительный) Как только вы закончите отладку, избавитесь от dealloc, который просто вызывает супер. Если вы пытаетесь найти память, которая никогда не освобождается, гораздо проще найти с помощью инструментов.
  • (Niggle) Для вашего метода тестирования рассмотрите вместо этого использование STAssetEquals(testCard.rank, 0, ...). Он тестирует одно и то же, но любая результирующая ошибка немного легче понять.
  • (Trivial) Вам необязательно объявлять методы тестирования единицы измерения в @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

автореферат был виновником. Я пропустил типизированные имена файлов, которые пишут вопрос, так что наконечник 4 не был проблемой. tip 2 - мой код содержит другие функции init, включая предложенный. Я хотел максимально ограничить свой код, пытаясь изолировать ошибку. – Joe

+0

Рад, что помогло. Убрал наконечник имен файлов, так как это была опечатка. Вы умны, чтобы опубликовать только код, вызвавший ошибку. :-) –

Смежные вопросы