为啥 GHUnit 的异步测试中的错误断言会使应用程序崩溃,而不仅仅是测试失败?

Posted

技术标签:

【中文标题】为啥 GHUnit 的异步测试中的错误断言会使应用程序崩溃,而不仅仅是测试失败?【英文标题】:Why does a false assertion in async test in GHUnit crash the app instead of just failing the test?为什么 GHUnit 的异步测试中的错误断言会使应用程序崩溃,而不仅仅是测试失败? 【发布时间】:2011-09-30 17:11:47 【问题描述】:

这个问题的浏览量很少,还没有答案。如果您有关于如何改变这个问题以获得更多眼球的建议,我很高兴听到他们的声音。干杯!

我正在使用GHAsyncTestCase 来测试我的自定义NSOperation。我将测试用例设置为操作对象的委托,完成后我在主线程上调用didFinishAsyncOperation

当断言失败时,它会抛出一个异常,该异常应该被测试用例捕获以将测试呈现为“失败”。但是,一旦断言失败,我的应用程序就会被 Xcode 中止,而不是这种预期的行为。

*** 由于未捕获的异常“GHTestFailureException”而终止应用程序,原因:“NO”应该为 TRUE。这应该会触发失败的测试,但会导致我的应用程序崩溃。'

我显然做错了什么。谁能告诉我?

@interface TestServiceAPI : GHAsyncTestCase
@end

@implementation TestServiceAPI

    - (BOOL)shouldRunOnMainThread
    
        return YES;
    

    - (void)testAsyncOperation
    
        [self prepare];

        MyOperation *op = [[[MyOperation alloc] init] autorelease];

        op.delegate = self; // delegate method is called on the main thread.

        [self.operationQueue addOperation:op];

        [self waitForStatus:kGHUnitWaitStatusSuccess timeout:1.0];
    

    - (void)didFinishAsyncOperation
    
        GHAssertTrue(NO, @"This should trigger a failed test, but crashes my app instead.");

        [self notify:kGHUnitWaitStatusSuccess forSelector:@selector(testAsyncOperation)];
    

@end

【问题讨论】:

我猜异常是在没有异常处理程序的上下文(例如不同的线程)中发生的。 是的,这也是我的猜测。但这必须是异步测试的标准问题场景,对吧?我该怎么做才能解决它? 我也遇到了同样的异常。但我使用 GHTestCase。当一个测试用例失败时,它是否也应该让应用崩溃? 不应该,您的应用程序崩溃的原因是测试套件的异常处理程序没有捕获您的异常。重构您的测试以不脱离测试方法。我建议你现在就开始使用 XCTest,甚至 Kiwi。 【参考方案1】:

当我终于休息一下时,我已经挖了一个星期来寻找解决方案。对一个赏金问题几乎没有意见,也没有人愿意尝试答案,这有点奇怪。我在想这个问题可能很愚蠢,但没有反对票,也没有人愿意纠正它。 *** 已经饱和了吗?

一个解决方案。

诀窍是不要从回调方法中断言任何内容,而是将断言放回原始测试中。 wait 方法实际上是阻塞线程,这是我之前没有想到的。如果您的异步回调接收到任何值,只需将它们存储在 ivar 或属性中,然后在您的原始测试方法中基于它们进行断言。

这会处理不导致任何崩溃的断言。

- (void)testAsyncOperation

    [self prepare];

    MyOperation *op = [[[MyOperation alloc] init] autorelease];

    op.delegate = self; // delegate method is called on the main thread.

    [self.operationQueue addOperation:op];

    // The `waitfForStatus:timeout` method will block this thread.
    [self waitForStatus:kGHUnitWaitStatusSuccess timeout:1.0];

    // And after the callback finishes, it continues here.
    GHAssertTrue(NO, @"This triggers a failed test without anything crashing.");


- (void)didFinishAsyncOperation

    [self notify:kGHUnitWaitStatusSuccess forSelector:@selector(testAsyncOperation)];

【讨论】:

太棒了!谢谢你(尽管它是前一段时间被问到的) 很高兴它有帮助!一个人必须喜欢这样存档的堆栈溢出:) 你是救世主我的朋友,我怎么想不到,为此苦苦挣扎了两天,但我认为 GHUnit 应该更恰当地处理它。我无法在块代码中断言布尔值。这固定了我的逻辑。虽然我不太喜欢使用 __block 变量,但它确实有效。 有史以来最好的评论:D。我可能会问,为什么你“仍然”使用 GHUnit,而不是 XCTest?【参考方案2】:

查看你的Xcode Breakpoints navigator,删除所有异常断点,就这样!!!

【讨论】:

谢谢你,永远忘记它。【参考方案3】:

查看 GHUnit 的头文件,看起来这可能是您的代码应该发生的情况。 GHUnit 的子类可以覆盖此方法:

// Override any exceptions; By default exceptions are raised, causing a test failure
- (void)failWithException:(NSException *)exception  

不抛出异常,但更简单的解决方案是使用 GHAssertTrueNoThrow 而不是 GHAssertTrue 宏。

【讨论】:

在我的实际测试中,我使用 OCHamcrest 来编写断言,因为 GHAssert* 语法与我喜欢读写断言的方式不匹配。感谢failWithException: 的建议,但我想我现在对自己的解决方案很满意。【参考方案4】:

我认为这个问题应该是“如何在 GHUnit 中使用块测试方法”?

答案可以在这里找到:http://samwize.com/2012/11/25/create-async-test-with-ghunit/

【讨论】:

以上是关于为啥 GHUnit 的异步测试中的错误断言会使应用程序崩溃,而不仅仅是测试失败?的主要内容,如果未能解决你的问题,请参考以下文章

在回调块中运行断言而不是在前端显示错误时,GHUnit 崩溃

使用异步 HTTP 获取操作的 GHUnit 测试

使用 mocha 和 chaiAsPromised 测试异步函数时的断言错误

Mocha,应该 - 在测试具有承诺的异步函数时,断言错误是沉默的

GHUnit 在 iOS 项目中转换为 ARC 后给出 allocate_pages() 错误

断言正在破坏 Mocha 测试中的异步功能