2011-11-12 15 views
9

Sé cómo resolver los problemas de EXC_BAD_ACCESS, pero no estoy seguro de cómo probarlo unitariamente. ¿Hay alguna forma de capturar EXC_BAD_ACCESS en código en lugar de simplemente colgar?¿Cómo pruebo la unidad para EXC_BAD_ACCESS?

Aquí es por lo que pido: He escrito una biblioteca que se utiliza mucho bloques, así:

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

En mi aplicación de doSomething: Voy a correr el tiempo del bloque, así:

myBlock(); 

Si una persona pasa a cero en el caso de la manzana, entonces se bloqueará con EXC_BAD_ACCESS, por lo que la solución es comprobar que existe el bloque, así:

if (myBlock) { 
    myBlock(); 
} 

Este cheque nil es bastante fácil de olvidar, así que me gustaría una forma de escribir una prueba unitaria que falla cuando se produce el bloqueo. Supongo que un bloqueo podría considerarse una falla de prueba, pero creo que sería mejor para otros que intentan ejecutar las pruebas ver un mensaje de error agradable en lugar de un bloqueo. ¿Algunas ideas?

Respuesta

4

Creo que tendrá que ejecutar la prueba en un subproceso; luego puedes dejar que el subproceso se bloquee, verificar ese bloqueo y fallar la prueba si ocurre.

Trabajando desde Peter Hosey's singleton test code.

- (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 prueba se ejecutará en sí en un subproceso de este modo:

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

} 

Es posible que tenga que ajustar este; No lo he probado.

+0

Esto es muy interesante. En el primer intento, termina fallando la prueba sin importar lo que haga, pero el proyecto está dirigido como una biblioteca estática Cocoa Touch, y al ejecutar las pruebas se lanza el simulador de iPhone. No creo que fork() vaya a funcionar allí, así que voy a probar esto como un objetivo de Mac/Cocoa y ver qué pasa. ¡Gracias! – greenisus

+0

Ooh, sí, no sé si 'fork()' está incluso disponible en iOS, lo siento.También estoy teniendo problemas para hacer que esto funcione del todo bien; Lo actualizaré si descubro algo. –

1

se recomienda usar una de las macros afirmación encontrados en la Assertions and Logging Programming Guide

Por lo que podría hacer algo como:

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

Esto hace cumplir las condiciones previas que deben cumplirse antes de que el método continúa ejecutándose. También permite que la aplicación se bloquee y le dará una razón por la que no sea EXEC_BAD_ACCESS.

+1

Esto realmente no ayuda con la prueba de la unidad; greenisus podría incluir igualmente el cheque 'if (myBlock) {myBlock()};' que mencionó en la pregunta. El problema, a menos que lo haya entendido completamente mal, es cómo escribir una prueba unitaria que capture _forgetting_ para verificar el bloque en el código bajo prueba. –

+0

Josh tiene razón. Podría usar esa afirmación, pero lo que estoy tratando de probar es que mis métodos no se bloquean cuando les paso un bloque nulo, de modo que no importa si myBlock es nulo o no. – greenisus

+0

Al usar la aserción, está garantizando que 'myBlock' no es nulo. Si tuviera que probar ese método con una prueba unitaria, la prueba fallaría debido a la falla de la aserción. –

Cuestiones relacionadas