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


这个问题的观点很少,也没有答案。如果你有什么建议要改变这个问题以获得更多的眼球,我会很高兴听到它们。干杯!

我在用着 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

10809
2017-09-30 17:11


起源

我猜测异常在上下文(例如,不同的线程)中发生,其中没有异常处理程序来捕获它。 - Hot Licks
是的,这也是我猜的。但这必须是异步测试的标准问题场景,对吧?我该怎么做才能解决这个问题? - epologee
我也得到了同样的例外。但我使用GHTestCase。当测试用例失败时,它是否应该使应用程序崩溃? - ArunaNZ
不,不应该,你的应用程序崩溃的原因是测试套件的异常处理程序没有捕获你的异常。重构您的测试以避免破坏测试方法。我建议你现在开始使用XCTest,甚至是Kiwi。 - epologee


答案:


当我终于休息一下时,我已经挖了一个星期才找到解决方案。在赏金问题上没有任何意见,并且没有人愿意尝试回答,这有点奇怪。我当时认为这个问题可能很愚蠢,但没有任何支持,也没有人愿意纠正它。 StackOverflow会变得饱和吗?

一个办法。

诀窍是不要从回调方法断言任何东西,而是将断言放回原始测试中。 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)];
}

12
2017-10-09 13:39



真棒!谢谢你(尽管前一段时间被问过) - MTurner
很高兴它有所帮助!一个人喜欢堆栈溢出这样存档:) - epologee
你是我的朋友的救星,我怎么想不到它,两天都在苦苦挣扎,但我认为GHUnit应该更恰当地处理它。我无法在块代码中声明一个布尔值。这解决了我的逻辑。虽然我不喜欢使用__block变量,但它确实有效。 - George Taskos
有史以来最好的评论:D。我可能会问,为什么你还在使用GHUnit而不是XCTest? - epologee


查找你的Xcode Breakpoints导航器,删除所有异常断点,这就是全部!


2
2018-03-29 03:19



谢谢你,永远忘了它。 - Rostyslav Druzhchenko


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

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

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


0
2017-10-09 13:47



在我的实际测试中,我使用OCHamcrest来编写断言,因为GHAssert *语法与我喜欢读取和写入断言的方式不匹配。谢谢你 failWithException: 建议,但我认为我现在对自己的解决方案感到满意。 - epologee
我很高兴你找到了解决方案。谢谢你的upvote。 - Ash Furrow


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

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


0
2018-02-19 17:14