【问题标题】:How do I unit test for EXC_BAD_ACCESS?如何对 EXC_BAD_ACCESS 进行单元测试?
【发布时间】:2011-11-12 21:30:00
【问题描述】:

我知道如何解决 EXC_BAD_ACCESS 问题,但我不确定如何对其进行单元测试。有没有办法在代码中捕获 EXC_BAD_ACCESS 而不是简单地崩溃?

这就是我问的原因:我编写了一个大量使用块的库,如下所示:

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

在我对doSomething: 的实现中,我将最终运行该块,如下所示:

myBlock();

如果调用者为 block 传递 nil,那么它会以EXC_BAD_ACCESS 崩溃,因此解决方案是检查 block 是否存在,如下所示:

if (myBlock) {
    myBlock();
}

这个 nil 检查很容易忘记,所以我想要一种方法来编写一个在崩溃发生时失败的单元测试。我想崩溃可以被认为是测试失败,但我认为其他人尝试运行测试以看到一个很好的失败消息而不是崩溃会更好。有什么想法吗?

【问题讨论】:

    标签: objective-c unit-testing ocunit


    【解决方案1】:

    我认为您需要在子进程中运行测试;然后你可以让子进程崩溃,检查那个崩溃,如果它发生了,就直接失败测试。

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

    然后每个测试将在一个子进程中运行,如下所示:

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

    您可能需要对此进行调整;我没有测试过。

    【讨论】:

    • 这很有趣。在第一次尝试时,无论我做什么,它最终都无法通过测试,但该项目的目标是 Cocoa Touch 静态库,并且运行测试会启动 iPhone 模拟器。我不认为 fork() 会在那里工作,所以我也会将它作为 Mac / Cocoa 目标进行尝试,看看会发生什么。谢谢!
    • 哦,是的,我不知道 fork() 是否在 iOS 上可用,抱歉。我也很难让它完全正常工作;如果我有什么发现,我会更新。
    • @greenisus 你有机会在 iOS 上成功解决这个问题吗?我也在寻找一种在发生崩溃时使测试失败的方法,尤其是在 Swift 中。
    【解决方案2】:

    我建议使用Assertions and Logging Programming Guide 中的断言宏之一

    所以你可以这样做:

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

    这强制了在方法继续执行之前必须满足的先决条件。它还允许应用程序崩溃,并会为您提供 EXEC_BAD_ACCESS 以外的原因。

    【讨论】:

    • 这对单元测试没有帮助; greenisus 同样可以包括他在问题中提到的if(myBlock){ myBlock() }; 检查。除非我完全误解了,否则问题是如何编写一个单元测试来捕获 forgetting 以检查被测代码中的块。
    • 乔希是对的。我可以很好地使用该断言,但我真正想要测试的是,当我向它们传递一个 nil 块时,我的方法不会崩溃,因此 myBlock 是否为 nil 无关紧要。
    • 通过使用断言,您保证myBlock 不为零。如果您要使用单元测试来测试该方法,则测试将由于断言失败而失败。
    • 这不是我要问的。我希望 nil 成为 myBlock 可接受的值,因此我正在寻找一个测试,以确保通过 nil 不会导致崩溃。
    • 明白了。我没有意识到这一点。
    猜你喜欢
    • 2012-01-08
    • 2019-11-02
    • 1970-01-01
    • 1970-01-01
    • 2013-09-30
    • 2019-01-05
    • 2011-03-16
    • 2013-01-02
    • 2020-04-23
    相关资源
    最近更新 更多