2011-11-12 16 views
9

EXC_BAD_ACCESS sorunlarını nasıl çözeceğimi biliyorum, ancak bunun için nasıl birim testi yapacağımı bilmiyorum. EXC_BAD_ACCESS kodunu basitçe kilitlemek yerine kodda yakalamanın bir yolu var mı? İşteEXC_BAD_ACCESS için nasıl birim testi yapabilirim?

soruyorum nedeni şudur: Böyle ağır blokları kullanan bir kütüphane yazdım:

doSomething: benim uygulamasında
- (void)doSomething:(void (^)())myBlock; 

böyle, sonuçta bloğu çalıştırmak için gidiyorum:

çözelti bloğu mevcut olduğunu kontrol etmek için, bu nedenle

bir arayan bloğu için nil geçerse

myBlock(); 
, o zaman, bu gibi, EXC_BAD_ACCESS kilitlenmesine:

if (myBlock) { 
    myBlock(); 
} 

Bu nil çekinin unutulması oldukça kolaydır, bu nedenle, çökme meydana geldiğinde başarısız olan bir birim testi yazmak için bir yol istiyorum. Bir çöküşün test başarısızlığı olarak düşünülebileceğini sanıyorum, ama sanırım bir kazadan ziyade güzel bir hata mesajı görmek için testleri çalıştırmaya çalışanların daha iyi olacağını düşünüyorum. Herhangi bir fikir? Bu şekilde çalışmaya devam yöntemle önce yerine getirilmesi gereken ön şartları zorlar

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

:

cevap

4

Sınama işlemini bir alt işlemde çalıştırmanız gerektiğini düşünüyorum; Daha sonra, alt işlemin çökmesine izin verebilir, bu kilitlenmeyi kontrol edebilir ve gerçekleştiğinde testi düzgün bir şekilde gerçekleştiremezsiniz.

Peter Hosey's singleton test code'den çalışıyor.

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

sonra her test şöyle bir alt süreç olarak kendisini yayınlanır:

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

} 

Bu değişiklikler yapmanızı gerektirecek; Ben test etmedim.

+0

Bu çok ilginç. İlk denemede, ne yaptığımın bir önemi yok, ama bu proje bir Cocoa Touch statik kütüphanesi olarak hedefleniyor ve testleri yürütmek iPhone Simulator'u başlatıyor. Fork() 'ın orada çalışacağını düşünmüyorum, bu yüzden bir Mac/Cocoa hedefi olarak da deneyeceğim ve ne olacağını göreceğim. Teşekkürler! – greenisus

+0

Ooh, evet, fork() 'iOS'ta bile kullanılabilir mi, bilmiyorum.Bunu tamamen doğru şekilde çalışmak için sorun yaşıyorum; Bir şey bulursam güncellenir. –

1

Ben Böylece gibi bir şey yapabileceğini Assertions and Logging Programming Guide

bulunan iddia makroları birini kullanarak öneririm. Ayrıca uygulamanın çökmesine izin verir ve EXEC_BAD_ACCESS dışında neden bir sebep verir.

+1

Bu, ünite testinde gerçekten yardımcı olmaz; greenisus eşit derecede iyi bir şekilde if if (myBlock) {myBlock()} 'ı içerebilir, 'soruda bahsettiğini kontrol edin. Sorun, tamamen yanlış anlamadığım sürece, test altındaki koddaki bloğu kontrol etmek için _forgetting_'ı yakalayan bir birim testinin nasıl yazılacağıdır. –

+0

Josh haklı. Bu iddiayı çok iyi kullanabildim, ama gerçekten denemeye çalıştığım şey, benim bir blok bloğunu geçtiğimde yöntemlerimin çökmemesidir, bu yüzden myBlock'un sıfır olup olmadığını farketmez. – greenisus

+0

İddiayı kullanarak, “myBlock” un nil olmadığını garanti ediyorsunuz. Bu yöntemi bir birim testi ile test edecekseniz, testin başarısız olması nedeniyle test başarısız olur. –