AFNetworking 单元测试

Posted

技术标签:

【中文标题】AFNetworking 单元测试【英文标题】:AFNetworking Unit Tests 【发布时间】:2014-08-15 17:40:47 【问题描述】:

我正在尝试使用以下代码进行单元测试。但是,测试只是挂在等待部分。我的测试代码如下。我是 ios 和 AFNetworking 的新手。任何帮助将不胜感激。

我知道的事情: 正在调用 USAPIConnection 中的方法。 在 TestController 上没有调用成功或失败方法。 对 rails api 的请求正在运行。 (我知道它会返回 200 OK 代码)。

我不知道的事情: AFHTTPRequestOperationManager 实际上是在发送请求吗? 为什么没有成功发送失败方法? 这个单元测试是否足以进行测试?

XC测试代码

#import <XCTest/XCTest.h>
#import "USAPIConnection.h"
#import "Controller.h"

@interface TestController : NSObject <Controller>

@property bool done;

@end

@implementation TestController

-(void)asynchronousSuccessfulWithObject:(id)object type:(int)type
    NSLog(@"Object: %@", object);
    XCTAssertNotNil(object,"@Should have returned JSON object: %s",__PRETTY_FUNCTION__);
    _done = true;


-(void)asynchronousUnsuccessfulWithError:(NSError *)error type:(int)type
    XCTFail(@"Unsuccessful async call with error%s: %s",error,__PRETTY_FUNCTION__);
    _done = true;


@end

@interface USAPIConnectionTests : XCTestCase

@end

@implementation USAPIConnectionTests

- (void)setUp

    [super setUp];
    NSLog(@"Beginning Test: %s",__PRETTY_FUNCTION__);


- (void)tearDown

    NSLog(@"Ending Test: %s",__PRETTY_FUNCTION__);
    [super tearDown];


- (void)testGetTeamById

    TestController* testController = [[TestController alloc] init];
    testController.done = false;
    [USAPIConnection getTeamById:1 controller:testController];
    int count = 0;
    while(!testController.done && count < 10)
        //Waiting
        [NSThread sleepForTimeInterval:3.0];
        count = count + 1;
    
    if(count == 10)
        XCTFail(@"Timed out: %s",__PRETTY_FUNCTION__);
    


@end

USAPIConnection 中调用的方法

+(void)getTeamById:(int)identity controller:(id<Controller>)controller
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    AFJSONResponseSerializer* serializer = [AFJSONResponseSerializer serializer];
    serializer.acceptableContentTypes = [NSSet setWithObject:@"application/json"];
    manager.responseSerializer = serializer;
    [manager POST:[NSString stringWithFormat:@"http://%@/team/%D",baseURL,identity] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) 
        [controller asynchronousSuccessfulWithObject:responseObject type:TYPETEAMSBYNAME];
     failure:^(AFHTTPRequestOperation *operation, NSError *error) 
        [controller asynchronousUnsuccessfulWithError:error type:TYPETEAMSBYNAME];
    ];

尝试

尝试将测试方法更改为以下。但是,测试控制器中的 NSLog 都没有运行。

- (void)testGetTeamById

    TestController* testController = [[TestController alloc] init];
    testController.done = false;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^[USAPIConnection getTeamById:1 controller:testController];);
    //dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^NSLog(@"HELLO FROM ASYNC QUEUE"););

【问题讨论】:

如果我错了,请纠正我,但是主线程不会在任何地方等待,所以当应该调用 asynchronousSuccessfulWithObject 时,程序已经不再运行了 @toasted_flakes 这是通过测试运行的,所以当测试 testGetTeamById 运行时,while 循环有一个短暂的等待,直到完成或大约 30 秒过去。 错误可能仍然来自那里,因为在 XCTest 中没有运行循环。要调试 XCTest 的异步行为,您可以从运行虚拟块开始,而不是使用 AFNetworking。类似于dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ NSLog(@"Hello from async queue"); ); @toasted_flakes 我不确定那会完成什么。你能进一步解释一下吗? 如果我对 XCTest 框架的理解是正确的,NSLog 将无法运行,因为缺少适当的 NSRunLoop 或等效项。然后我们就可以排除AFNetworking具体使用中的任何错误 【参考方案1】:

Xcode 6(撰写本文时尚未发布)中的 XCTest 支持异步方法的测试。

这是 Swift 中的一个小 sn-p,它显示了它的外观:

假设你有一个以完成函数为参数的异步方法:

func doSomethingAsync(completion:(result: Int?, error: Int?) -> ())

现在,您想测试此异步函数是否成功执行,或者您想测试您在延续(完成处理程序)中定义的一些代码:

func testAsyncFunction() 
    let expect = self.expectationWithDescription("completion handler called")
    doSomethingAsync  (result, error) -> () in
        if let value = result? 
            println("Result: \(value)")
        
        else 
            println("Error: \(error!)")
        
        expect.fulfill()
    
    waitForExpectationsWithTimeout(1000, handler: nil)

您可以在 XCTest 的标题中阅读有关 XCTest self.expectationWithDescription: fulfillwaitForExpectationsWithTimeout: 的新方法的更多信息。

我现在正在使用这个新的异步测试工具进行单元测试。只是缺少一些功能,例如在 fulfill 旁边有一个方法 reject 和一个可选的用于记录的字符串参数。 IMO,它看起来很吸引人,到目前为止效果很好。所以,我真的鼓励你看看 Xcode 测试版;

与此同时,您可能会发现一个“promise”库适用于实现异步方法的测试。我建议在这个论坛中多次使用 RXPromise 库(我是作者)进行单元测试。 ;)

【讨论】:

除了@CouchDeveloper 回答的内容之外,我建议使用 OHHTTPStubs 来存根服务器响应。 github.com/AliSoftware/OHHTTPStubs【参考方案2】:

在 UnitTest 中进行异步调用需要标志之类的东西。这里讨论的太多了:

How to unit test asynchronous APIs?

【讨论】:

以上是关于AFNetworking 单元测试的主要内容,如果未能解决你的问题,请参考以下文章

在单元测试中使用 AFNetworking 监控可达性失败

信号量等待导致 AFNetworking 阻塞?

生成新单元格时清除集合视图单元格(iOS7 - AFNetworking)

raywenderlich 的 AFNetworking 教程不在表格单元格上显示数据

Django单元测试测试视图问题,怎么解决

.NET 单元测试的艺术&单元测试之道C#版