Hoe eenheidstest ik voor EXC_BAD_ACCESS?

Ik weet hoe ik EXC_BAD_ACCESS-problemen moet oplossen, maar ik weet niet zeker hoe ik het moet testen. Is er een manier om EXC_BAD_ACCESS vast te leggen in code in plaats van gewoon te crashen?

Dit is waarom ik vraag: ik heb een bibliotheek geschreven die zwaar blokken gebruikt, zoals deze:

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

In mijn implementatie van doSomething: zal ik het blok uiteindelijk als volgt uitvoeren:

myBlock();

Als een beller nul doorgeeft voor het blok, crasht het met EXC_BAD_ACCESS , dus de oplossing is om te controleren of het blok bestaat, zoals dit:

if (myBlock) {
    myBlock();
}

Deze nulcontrole is vrij eenvoudig te vergeten, dus ik zou graag een manier willen om een ​​eenheidscontrole uit te voeren die mislukt wanneer de crash optreedt. Ik veronderstel dat een crash kan worden beschouwd als een testfout, maar ik denk dat het leuker is voor anderen die proberen de tests uit te voeren om een ​​mooie foutmelding te zien in plaats van een crash. Om het even welke ideeën?

9

2 antwoord

Ik denk dat je de test in een subproces moet uitvoeren; dan kun je het subproces laten crashen, controleren op die crash en de test feilloos laten mislukken als deze zich voordoet.

Werken met Peter Hosey's singleton-testcode .

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

Elke test zal zichzelf dan in een subproces uitvoeren zoals:

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

}

Misschien moet je dit aanpassen; Ik heb het niet getest.

4
toegevoegd
Ooh, ja, ik weet niet of fork() zelfs beschikbaar is op iOS, sorry. Ik heb problemen om dit ook volledig goed te laten werken; Ik zal updaten als ik iets bedacht.
toegevoegd de auteur Josh Caswell, de bron
Dit is erg interessant. Bij de eerste poging mislukt de test, ongeacht wat ik doe, maar het project is bedoeld als een statische bibliotheek van Cocoa Touch en bij het uitvoeren van de tests wordt de iPhone Simulator gestart. Ik denk niet dat fork() daar gaat werken, dus ik zal dit ook proberen als een Mac/Cocoa-doelwit en zien wat er gebeurt. Bedankt!
toegevoegd de auteur greenisus, de bron

I would suggest using one of the assertion macros found in the Assertions and Logging Programming Guide

U zou dus iets kunnen doen als:

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

Dit dwingt de randvoorwaarden af ​​waaraan moet worden voldaan voordat de methode wordt voortgezet. Hiermee kan de app ook crashen en krijgt u een andere reden dan EXEC_BAD_ACCESS.

1
toegevoegd
Dit helpt niet echt bij het testen van de unit; greenisus kan net zo goed de if (myBlock) {myBlock ()}; controle bevatten die hij in de vraag heeft genoemd. Het probleem is, tenzij ik het volledig verkeerd heb begrepen, hoe ik een eenheidscontrole moet schrijven die vergeet om het blok in de te testen code te controleren.
toegevoegd de auteur Josh Caswell, de bron
Josh heeft gelijk. Ik zou die bewering heel goed kunnen gebruiken, maar wat ik echt probeer te testen is dat mijn methoden niet crashen als ik ze een nul blok geef, zodat het niet uitmaakt of mijn Block nul is of niet.
toegevoegd de auteur greenisus, de bron
Dat is niet wat ik vraag. Ik wil dat nihil een acceptabele waarde is voor myBlock, dus ik ben op zoek naar een test die ervoor zorgt dat niets doen geen crash veroorzaakt.
toegevoegd de auteur greenisus, de bron
Door de bewering te gebruiken, garandeert u dat myBlock niet nul is. Als u die methode zou testen met een eenheidscontrole, zou de test mislukken vanwege het falen van de bewering.
toegevoegd de auteur Brandon A, de bron
Gotcha. Dat wist ik niet.
toegevoegd de auteur Brandon A, de bron