Ответ 1
Я встречал это много раз сам, и это всегда раздражало. В основном, это обычно означает, что ваши тесты устройств сработали, но не помогают изолировать ошибку. Если тесты модуля выдают результат перед сбоем (open Build > Build Results), вы обычно можете получить представление о том, какой тест выполнялся при возникновении проблемы, но это само по себе не слишком полезно.
Лучшим общим предложением для отслеживания причины является отладить ваши модульные тесты. При использовании OCUnit это, к сожалению, сложнее, чем выбор Run > Debug. Тем не менее, в том же учебнике, который вы используете, есть раздел в нижней части под названием " Использование отладчика с OCUnit", в котором объясняется, как создать пользовательский исполняемый файл в Xcode для выполнения модульных тестов таким образом, чтобы отладчик может подключаться. Когда вы это сделаете, отладчик остановится там, где произошла ошибка, вместо того, чтобы получить загадочный "код 138", когда все идет пламенем.
Хотя я не могу точно угадать, что вызывает ошибку, у меня есть несколько предложений...
- НИКОГДА, НИКОГДА не проверяйте autorelease
self
в методе init - это нарушает правила хранения с сохранением-освобождением. Это само по себе приведет к сбоям, если объект будет выпущен неожиданно. Например, в вашем методе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) Вам не нужно объявлять методы unit test в
@interface
. OCUnit динамически запускает любой метод формата-(void)test...
для вас. Это не помешает объявить их, но вы сэкономите себя на машинке, если просто опустите их. В связанной заметке у меня обычно есть только .m файл для модульных тестов и помещаем раздел @interface в начало этого файла. Это отлично работает, поскольку никто не должен включать мой интерфейс unit test. - (Простота) Если вы не подклассом
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