测试是否遵守NSURLSessionConfiguration设置

时间:2015-12-16 03:35:18

标签: ios nsurlsession nsurlprotocol nsurlsessionconfiguration

我创建了一个带有一些默认设置的NSURLSessionConfiguration但是当我在自定义NSURLProtocol中看到使用该配置创建的请求对象时,似乎所有这些设置都没有被继承,我有点困惑。

NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];

NSMutableArray *protocolsArray = [NSMutableArray arrayWithArray:config.protocolClasses];

[protocolsArray insertObject:[CustomProtocol class] atIndex:0];

config.protocolClasses = protocolsArray;

// ex. set some random parameters

[config setHTTPAdditionalHeaders:@{@"Authorization":@"1234"}];
[config setAllowsCellularAccess:NO];
[config setRequestCachePolicy:NSURLRequestReturnCacheDataElseLoad];
[config setHTTPShouldSetCookies:NO];
[config setNetworkServiceType:NSURLNetworkServiceTypeVoice];
[config setTimeoutIntervalForRequest:4321];

// Create a request with this configuration and start a task

NSURLSession* session = [NSURLSession sessionWithConfiguration:config];

NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://google.com"]];

NSURLSessionDataTask* task = [session dataTaskWithRequest:request];

[task resume];

在我注册的自定义NSURLProtocol中

- (void)startLoading {
    ...

    // po [self.request valueForHTTPHeaderField:@"Authorization"] returns 1234
    //
    // However, I'm very confused why
    //
    //  - allowsCellularAccess
    //  - cachePolicy
    //  - HTTPShouldHandleCookies
    //  - networkServiceType
    //  - timeoutInterval
    //
    // for the request return the default values unlike for the header

    ...

}

有没有办法检查我设置的那些参数是否被请求服从并继承?

1 个答案:

答案 0 :(得分:0)

在处理http请求时,从基础知识开始是有帮助的,例如操作系统实际发出的请求,是否收到响应?这将部分有助于回答有关检查请求是否遵守设置参数的问题。

我会质疑您在短语中使用"继承" 这个词

  

有没有办法检查我设置的那些参数是否被请求服从并继承?

面向对象编程中的继承具有非常特定的含义。你实际上是否创建了具有特定属性的NSURLRequest的自定义子类(让它称之为SubClassA),然后是另一个子类(让它称之为SubClassB),并期望第二个子类(SubClassB)到从其父级(SubClassA)继承属性?如果是这样,肯定不会在您提供的代码中指出。

有几个HTTP代理程序可用于帮助确认是否正在发送HTTP请求,是否收到响应,还允许您检查请求和响应的详细信息。 Charles HTTP Proxy就是这样一个程序。使用Charles,我能够确定您提供的代码没有发出任何HTTP请求。因此,如果没有提出请求,您无法确认或拒绝任何参数。

通过将包含CustomProtocol的行注释掉作为NSURLSession配置的一部分,并使用或不使用这些行运行代码,我获得了一些可能有价值的信息:

  1. 通过注释掉包括CustomProtocol在内的行,实际上发出了一个请求(并且失败了),这是Charles HTTP Proxy的通知。我还为方法dataTaskWithRequest添加了一个完成块。当CustomProtocol配置行被注释掉时,此完成块被点击。 CustomProtocol的startLoading方法未被点击。
  2. 当离开原始行以使用CustomProtocol配置NSURLSession时,Charles HTTP Proxy没有记录请求,并且完成处理程序未命中。但是,CustomProtocol的startLoading方法已被命中。
  3. 请参阅下面的代码(对原始问题中发布的代码进行了修改)。

    NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
    
    NSMutableArray *protocolsArray = [NSMutableArray arrayWithArray:config.protocolClasses];
    
    //[protocolsArray insertObject:[CustomProtocol class] atIndex:0];
    
    //config.protocolClasses = protocolsArray;
    
    // ex. set some random parameters
    
    [config setHTTPAdditionalHeaders:@{@"Authorization":@"1234"}];
    [config setAllowsCellularAccess:NO];
    [config setRequestCachePolicy:NSURLRequestReturnCacheDataElseLoad];
    [config setHTTPShouldSetCookies:NO];
    [config setNetworkServiceType:NSURLNetworkServiceTypeVoice];
    [config setTimeoutIntervalForRequest:4321];
    
    // Create a request with this configuration and start a task
    
    NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
    
    NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://google.com"]];
    
    NSURLSessionDataTask* task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                NSString * auth = [request valueForHTTPHeaderField:@"Authorization"];
                                                NSLog(@"Authorization: %@", auth);
                                                BOOL allowsCellular = [request allowsCellularAccess];
                                                NSString * allowsCellularString = allowsCellular ? @"YES" : @"NO";
                                                NSLog(@"Allows cellular: %@", allowsCellularString);
    }];
    
    [task resume];
    

    这将为您提供CustomProtocol未正确处理请求的信息。是的,当CustomProtocol配置为NSURLSession的一部分时,startLoading方法内的断点被命中,但这并不是CustomProtocol正确处理请求的明确证据。使用CustomProtocol需要执行许多步骤,如Apple(Protocol SupportNSURLProtocol Class Reference所述,您应该确认您正在关注它。

    要确保有些事情正在发挥作用:

    • 如果您使用的是CustomProtocol,则表示您可能尝试处理除http,https,ftp,ftps等之外的其他协议。
    • 确保您的终点(正在侦听http请求和响应的服务器)实际上可以接受请求并回复。
    • 如果您要设置HTTP授权标头,请确保服务器可以正确响应,并且如果您希望得到肯定响应,则凭据有效
    • 记得注册您的CustomProtocol

    例如:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
        [NSURLProtocol registerClass:[CustomProtocol class]];
        return YES;
    }
    

    下面是一个单元测试,用于验证NSURLSession是否按预期运行(未明确使用我们的自定义协议)。请注意,此单元测试在添加到Apple自己的项目CustomHTTPProtocol的示例代码时确实通过,但未使用我们的非常裸骨CustomProtocol

    - (void)testNSURLSession {
        XCTestExpectation *expectation = [self expectationWithDescription:@"Testing standard NSURL Session"];
    
        [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    #pragma unused(data)
            XCTAssertNil(error, @"NSURLSession test failed with error: %@", error);
            if (error == nil) {
                NSLog(@"success:%zd / %@", (ssize_t) [(NSHTTPURLResponse *) response statusCode], [response URL]);
                [expectation fulfill];
            }
        }] resume];
    
        [self waitForExpectationsWithTimeout:3.0 handler:^(NSError * _Nullable error) {
            if(nil != error) {
                XCTFail(@"NSURLSession test failed with error: %@", error);
            }
        }];
    }
    

    下面是一个单元测试,可用于在使用我们自己的NSURLSession类进行配置时验证对CustomProtocol所做的配置是否符合预期。同样,请注意,此测试使用CustomProtocol的空实现失败,但如果使用测试驱动开发(首先创建测试,然后是允许测试通过的代码秒),这是预期的。

    - (void)testCustomProtocol {
        XCTestExpectation *expectation = [self expectationWithDescription:@"Testing Custom Protocol"];
    
        NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];
        NSMutableArray *protocolsArray = [NSMutableArray arrayWithArray:config.protocolClasses];
    
        [protocolsArray insertObject:[CustomProtocol class] atIndex:0];
    
        config.protocolClasses = protocolsArray;
    
        // ex. set some random parameters
    
        [config setHTTPAdditionalHeaders:@{@"Authorization":@"1234"}];
        [config setAllowsCellularAccess:NO];
        [config setRequestCachePolicy:NSURLRequestReturnCacheDataElseLoad];
        [config setHTTPShouldSetCookies:NO];
        [config setNetworkServiceType:NSURLNetworkServiceTypeVoice];
        [config setTimeoutIntervalForRequest:4321];
    
        // Create a request with this configuration and start a task
        NSURLSession* session = [NSURLSession sessionWithConfiguration:config];
        NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.apple.com"]];
    
        NSURLSessionDataTask* task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    #pragma unused(data)
            XCTAssertNil(error, @"test failed: %@", error.description);
            if (error == nil) {
                NSLog(@"success:%zd / %@", (ssize_t) [(NSHTTPURLResponse *) response statusCode], [response URL]);
                NSString * auth = [request valueForHTTPHeaderField:@"Authorization"];
                NSLog(@"Authorization: %@", auth);
                XCTAssertNotNil(auth);
    
                BOOL allowsCellular = [request allowsCellularAccess];
                XCTAssertTrue(allowsCellular);
    
                XCTAssertEqual([request cachePolicy], NSURLRequestReturnCacheDataElseLoad);
    
                BOOL shouldSetCookies = [request HTTPShouldHandleCookies];
                XCTAssertTrue(shouldSetCookies);
    
                XCTAssertEqual([request networkServiceType], NSURLNetworkServiceTypeVoice);
    
                NSTimeInterval timeOutInterval = [request timeoutInterval];
                XCTAssertEqualWithAccuracy(timeOutInterval, 4321, 0.01);
                [expectation fulfill];
    
            }
    
        }];
    
        [task resume];
    
        [self waitForExpectationsWithTimeout:3.0 handler:^(NSError * _Nullable error) {
            if(nil != error) {
                XCTFail(@"Custom Protocol test failed with error: %@", error);
            }
        }];
    }