Como faço o teste de unidade para EXC_BAD_ACCESS?

9

Eu sei como resolver problemas de EXC_BAD_ACCESS, mas não sei como testar a unidade para isso. Existe uma maneira de capturar EXC_BAD_ACCESS no código em vez de simplesmente travar?

Eis por que pergunto: escrevi uma biblioteca que usa intensamente blocos, como este:

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

Na minha implementação de doSomething: , acabarei por executar o bloco, desta forma:

myBlock();

Se um chamador passar nil para o bloco, ele irá falhar com EXC_BAD_ACCESS , então a solução é verificar se o bloco existe, assim:

if (myBlock) {
    myBlock();
}

Essa verificação nula é fácil de esquecer, então eu gostaria de escrever um teste de unidade que falha quando a falha ocorre. Eu suponho que uma falha poderia ser considerada uma falha de teste, mas eu acho que seria melhor para os outros que tentassem executar os testes para ver uma boa mensagem de falha ao invés de uma falha. Alguma idéia?

    
por greenisus 12.11.2011 в 22:30
fonte

2 respostas

4

Acho que você precisará executar o teste em um subprocesso; então você pode deixar o subprocesso travar, verificar a falha e reprovar o teste corretamente, se ocorrer.

Trabalhando no código de teste singleton de Peter Hosey .

- (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));
        }
}

Cada teste será executado em um subprocesso assim:

- (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.");

}

Você pode precisar ajustar isso; Eu não testei isso.

    
por Josh Caswell 12.11.2011 / 23:12
fonte
1

Sugiro usar uma das macros de asserção encontradas na Guia de Programação de Asserções e Logging

Então você poderia fazer algo como:

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

Isso impõe as pré-condições que devem ser atendidas antes que o método continue sendo executado. Ele também permite que o aplicativo trave e fornecerá um motivo pelo qual você não é EXEC_BAD_ACCESS.

    
por Brandon A 12.11.2011 / 23:11
fonte