Как мне выполнить модульный тест для EXC_BAD_ACCESS? - PullRequest
10 голосов
/ 13 ноября 2011

Я знаю, как решить проблемы EXC_BAD_ACCESS, но я не уверен, как выполнить юнит-тестирование.Есть ли способ захватить EXC_BAD_ACCESS в коде вместо простого сбоя?

Вот почему я спрашиваю: я написал библиотеку, которая интенсивно использует блоки, например:

- (void)doSomething:(void (^)())myBlock;

В моей реализациииз doSomething: Я собираюсь в конечном итоге запустить блок, например так:

myBlock();

Если вызывающий абонент пропустит nil для блока, то произойдет сбой с EXC_BAD_ACCESS, поэтому решение состоит в том, чтобы проверитьчто этот блок существует, например:

if (myBlock) {
    myBlock();
}

Эту проверку на ноль довольно легко забыть, поэтому я хотел бы написать способ, который завершится неудачно при возникновении сбоя.Я полагаю, что сбой можно считать неудачей теста, но я думаю, что другим было бы лучше, если бы другие пытались запустить тесты, чтобы увидеть хорошее сообщение об ошибке, а не сбой.Есть идеи?

Ответы [ 2 ]

4 голосов
/ 13 ноября 2011

Я думаю, вам нужно запустить тест в подпроцессе; затем вы можете разрешить сбой подпроцесса, проверить его и аккуратно провалить тест, если он произойдет.

Работа с Синглтон-тестовый код Питера Хоси .

- (void) runTestInSubprocess:(SEL)testCmd {
        pid_t pid = fork();
        // The return value of fork is 0 in the child process, and it is
        // the id of the child process in the parent process.
        if (pid == 0) {
            // Child process: run test
            // isInSubprocess is an ivar of your test case class
            isInSubprocess = YES;
            [self performSelector:testCmd];
            exit(0);
        } else {
            // Parent process: wait for child process to end, check 
            // its status
            int status;
            waitpid(pid, &status, /*options*/ 0);
            // This was a crash; fail the test
            STAssertFalse(WIFSIGNALED(status), @"Test %@ crashed due to signal %d", NSStringFromSelector(testCmd), WTERMSIG(status));
        }
}

Каждый тест затем будет выполняться в подпроцессе следующим образом:

- (void) testSomething {
    if (!isInSubprocess) {
            // Hand off this test's selector to be run in a subprocess
            [self runTestInSubprocess:_cmd];
            return;
    }

    // Put actual test code here
    STAssertEquals(1, 1, @"Something wrong with the universe.");

}

Возможно, вам придется настроить это; Я не проверял это.

1 голос
/ 13 ноября 2011

Я бы предложил использовать один из макросов утверждений, приведенных в Руководстве по программированию утверждений и ведения журналов

Так что вы можете сделать что-то вроде:

NSAssert(myBlock != nil, @"myBlock must not be nil")

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

...