2011-11-12 26 views
9

Tôi biết cách giải quyết các vấn đề EXC_BAD_ACCESS, nhưng tôi không chắc chắn làm thế nào để kiểm tra đơn vị cho nó. Có cách nào để nắm bắt EXC_BAD_ACCESS trong mã thay vì chỉ đơn giản là bị rơi không?Tôi làm cách nào để kiểm tra đơn vị cho EXC_BAD_ACCESS?

Dưới đây là lý do tại sao tôi hỏi: Tôi đã viết một thư viện mà chủ yếu sử dụng các khối, như thế này:

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

Trong thực hiện của tôi doSomething: Tôi sẽ để cuối cùng chạy block, như thế này:

myBlock(); 

Nếu một người gọi đi nil cho khối, sau đó nó sẽ sụp đổ với EXC_BAD_ACCESS, vì vậy giải pháp là để kiểm tra xem khối tồn tại, như thế này:

if (myBlock) { 
    myBlock(); 
} 

Kiểm tra nil này khá dễ quên, vì vậy tôi muốn cách viết một bài kiểm tra đơn vị không thành công khi xảy ra sự cố. Tôi cho rằng một vụ tai nạn có thể được coi là một thử nghiệm thất bại, nhưng tôi nghĩ rằng nó sẽ là đẹp hơn cho những người khác cố gắng chạy các bài kiểm tra để xem một thông điệp thất bại tốt đẹp chứ không phải là một vụ tai nạn. Bất kỳ ý tưởng?

Trả lời

4

Tôi nghĩ bạn sẽ cần chạy thử nghiệm trong một tiến trình con; sau đó bạn có thể cho phép các vụ tai nạn subprocess, kiểm tra cho vụ tai nạn đó, và không kiểm tra gọn gàng nếu nó xảy ra.

Làm việc từ 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)); 
     } 
} 

Mỗi bài kiểm tra sau đó sẽ tự chạy trong một tiến trình con như vậy:

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

} 

Bạn có thể cần phải tinh chỉnh này; Tôi chưa thử nghiệm nó.

+0

Điều này rất thú vị. Lúc đầu, nó kết thúc thất bại trong việc kiểm tra bất kể tôi làm gì, nhưng dự án được nhắm mục tiêu như là một thư viện Cocoa Touch tĩnh, và chạy các thử nghiệm khởi chạy iPhone Simulator. Tôi không nghĩ rằng fork() sẽ làm việc ở đó, vì vậy tôi sẽ cố gắng này ra như là một mục tiêu Mac/Cocoa là tốt và xem những gì sẽ xảy ra. Cảm ơn! – greenisus

+0

Ooh, vâng, tôi không biết liệu 'fork()' có khả dụng trên iOS hay không, xin lỗi.Tôi đang gặp khó khăn khi làm việc này cũng hoàn toàn đúng; Tôi sẽ cập nhật nếu tôi tìm ra bất cứ điều gì. –

1

tôi sẽ đề nghị sử dụng một trong những macro khẳng định tìm thấy trong Assertions and Logging Programming Guide

Vì vậy, bạn có thể làm điều gì đó như:

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

này thực thi các điều kiện tiên quyết phải được đáp ứng trước khi phương pháp tiếp tục thực hiện. Nó cũng cho phép ứng dụng gặp sự cố và sẽ cung cấp cho bạn lý do tại sao khác với EXEC_BAD_ACCESS.

+1

Điều này thực sự không giúp ích gì đối với thử nghiệm đơn vị; greenisus cũng có thể bao gồm 'if (myBlock) {myBlock()};' kiểm tra xem anh ta đã đề cập trong câu hỏi chưa. Vấn đề, trừ khi tôi đã hoàn toàn hiểu lầm, là làm thế nào để viết một bài kiểm tra đơn vị mà bắt _forgetting_ để kiểm tra khối trong mã được thử nghiệm. –

+0

Josh đúng. Tôi rất có thể sử dụng khẳng định đó, nhưng những gì tôi thực sự cố gắng để kiểm tra là phương pháp của tôi không sụp đổ khi tôi vượt qua chúng một khối nil, để nó không quan trọng hay không myBlock là nil. – greenisus

+0

Bằng cách sử dụng xác nhận, bạn đảm bảo rằng 'myBlock' không phải là số không. Nếu bạn đã thử nghiệm phương thức đó với một phép thử đơn vị, phép thử sẽ thất bại do xác nhận không thành công. –

Các vấn đề liên quan