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

Posted

技术标签:

【中文标题】在回调块中运行断言而不是在前端显示错误时,GHUnit 崩溃【英文标题】:GHUnit crashes when running assertion in callback block instead of showing error on front end 【发布时间】:2012-02-14 02:05:47 【问题描述】:

在回调中使用任何断言都会导致 GH-Unit 应用程序崩溃。断言在其他地方也能正常工作。

这里有一个类似的问题:Why does a false assertion in async test in GHUnit crash the app instead of just failing the test?

但我不明白如何在我的情况下使用此解决方案。

- (void)testLoadMyProfile 

    void(^successCallback)(NSString*);
    successCallback = ^(NSString* response) 

        NSRange textRange;
        textRange =[[response lowercaseString] rangeOfString:[@"syntactically incorrect" lowercaseString]];

        if(textRange.location != NSNotFound) 
            GHFail(@"the request was syntactically incorrect");
        

        NSDictionary *d;        
        @try 
            d = [response JSONValue];    
         @catch (NSException *exception) 
            GHAssertNotNil(d, @"The response was not a valid JSONValue");
        

        GHAssertNotNil([d objectForKey:@"memberId"], @"memberId wasn't in response");
        GHAssertNotNil([d objectForKey:@"profile"], @"profile wasn't in response");
        GHAssertNotNil([d objectForKey:@"name"], @"profile wasn't in response");
        GHAssertNotNil([d objectForKey:@"surnamez"], @"profile wasn't in response");
    ;

    void(^errorCallback)(NSString*);
    errorCallback = ^(NSString* response) 
        GHFail(@"the error callback was called");
    ;    

    // this is using ASIHTTPRequest to retrieve data
    [[RestAPIConnector sharedInstance] loadMyProfile:successCallback :errorCallback];

我可以通过覆盖此方法来阻止应用程序崩溃 - 我什至可以记录异常,但测试不会在前端显示为失败。理想情况下,我希望它显示在前端,以便非技术人员可以运行测试并查看一切正常。

- (void)failWithException:(NSException *)exception 


【问题讨论】:

【参考方案1】:

你应该改变状态来停止块运行循环,检查我的 cmets:(对不起我的英语不好)

首先,您必须继承 GHAsyncTestCase

-(void)testGetRequest
    [self prepare]; //prepare for hook the run loop

    PLRequest *req=[PLRequest requestWithURL:[NSURL URLWithString:@"http://m.baidu.com"]];
    req.finishCallback=^(PLRequest *req)
        NSData *d=req.respondData;

        NSString *s=[NSString stringWithUTF8String:[d bytes]];

        GHTestLog(@"Finish:%@", s);
        [self notify:kGHUnitWaitStatusSuccess]; //here to return
    ;

    [req start];

    [self waitForStatus:kGHUnitWaitStatusSuccess timeout:15]; //wait for your block change Status then if timeout you will get a 'crash'


【讨论】:

所有断言 (GHAssertNotNil,GHAssertEqualObjects) 仍然使用 SIGBART 杀死应用程序。 :(【参考方案2】:

答案(你指向的)here 也应该对你有用。

所以你应该像之前提到的 Travis 那样实现 GHAsyncTestCase。拥有 Async 基类,您可以使用 waitForStatus:timeout: 和相应的 notify:forSelector: 方法。所有断言都需要在waitForStatus:timeout: 之后完成。此方法暂停运行循环并等待回调完成。

如果您需要有关异步测试的更多信息,请查看samples of GHUnit。

所以在你的情况下,我会尝试这样的事情:

- (void)testLoadMyProfile 

//Local variable for later assertion. __block is necessary to use the variable in the block.  
__block NSDictionary *d = nil;  

//Preparing.  
[self prepare];

void(^successCallback)(NSString*);
successCallback = ^(NSString* response) 

    NSRange textRange;
    textRange =[[response lowercaseString] rangeOfString:[@"syntactically incorrect" lowercaseString]];

    if(textRange.location != NSNotFound) 
        GHFail(@"the request was syntactically incorrect");
    

    // Declared before.
    // NSDictionary *d;

    @try 

        d = [response JSONValue];    

     @catch (NSException *exception) 

        // We'll check that later.
        // GHAssertNotNil(d, @"The response was not a valid JSONValue");
    

    // Later.
    //GHAssertNotNil([d objectForKey:@"memberId"], @"memberId wasn't in response");
    //GHAssertNotNil([d objectForKey:@"profile"], @"profile wasn't in response");
    //GHAssertNotNil([d objectForKey:@"name"], @"profile wasn't in response");
    //GHAssertNotNil([d objectForKey:@"surnamez"], @"profile wasn't in response");

    // we notify ourself that we are done. selector should point to this method!  
   [self notify:kGHUnitWaitStatusSuccess forSelector:@selector(testLoadMyProfile)];  

;

void(^errorCallback)(NSString*);
errorCallback = ^(NSString* response) 
    GHFail(@"the error callback was called");

    // in this case we do notify ourself that the request failed.  
   [self notify:kGHUnitWaitStatusFailure forSelector:@selector(testLoadMyProfile)];

;    

[[RestAPIConnector sharedInstance] loadMyProfile:successCallback :errorCallback];

// This line pauses the runloop for the length of the timeout
[self waitForStatus:kGHUnitWaitStatusSuccess timeout:10.0];

// And finally after this line you can do your assertions. As the code pauses until you notify it or the timeout fires.
GHAssertNotNil(d, @"The response was not a valid JSONValue");
GHAssertNotNil([d objectForKey:@"memberId"], @"memberId wasn't in response");
GHAssertNotNil([d objectForKey:@"profile"], @"profile wasn't in response");
GHAssertNotNil([d objectForKey:@"name"], @"profile wasn't in response");
GHAssertNotNil([d objectForKey:@"surnamez"], @"profile wasn't in response");


所以异步测试的所有断言都需要在waitForStatus:timeout: 之后完成。不要忘记notify:forSelector

【讨论】:

以上是关于在回调块中运行断言而不是在前端显示错误时,GHUnit 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 pyspark 在数据块中循环数据框列

当运行块中存在无限循环时,工厂中的 $http 成功回调未运行

Flutter 换屏回调

断言失败:第 22 行 pos 14: 'url != null': is not true

节点:断言:400 抛出错误; ^ AssertionError [ERR_ASSERTION]:指定的回调对象无效

forEach on map function js断言测试未运行