URLMock 1.3.6

URLMock 1.3.6

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布最新发布2021年1月

Cocoapods AdminDuncan LewisPrachi Gauriar 维护。



URLMock 1.3.6

  • 作者
  • Prachi Gauriar

URLMock

Build Status codecov

URLMock 是一个用于模拟和存根 URL 请求和响应的 Objective-C 框架。它与基于 Foundation NSURL 加载系统的 API(例如 NSURLConnection、NSURLSession 和 AFNetworking)一起工作,几乎不需要修改您的代码。

特性

  • 简单、文档丰富的 Objective-C API
  • 必要的设置最小化
  • 与基于 Foundation NSURL 加载系统的 API 一起工作
  • 考虑到响应存根和单元测试设计
  • 可用于项目部分或全部 URL 请求
  • 经过充分测试,包括许多有用的测试工具
  • 适用于 macOS、iOS 和 tvOS

URLMock 1.3.6 新增功能

URLMock 1.3.6 添加了对使用 Swift Package Manager 进行安装的支持。

安装

要开始使用 URLMock,最简单的方法是使用 CocoaPods 进行安装。

pod 'URLMock'

安装子规格

URLMock 有两个 CocoaPods 子规格,分别是 TestHelpersSubclassResponsibility。其中 TestHelpers 包含了一大类有用的测试函数。更多详情请参阅 UMKTestUtilities.h。您可以通过向 Podfile 添加以下行进行安装

pod 'URLMock/TestHelpers'

同样,通过向 Podfile 添加以下行可以安装 SubclassResponsibility 子规格

pod 'URLMock/SubclassResponsibility'

此子规格向 NSException 添加方法,以便于为必须由子类提供实现的函数抛出异常。更多详情请参阅 NSException+UMKSubclassResponsibility.h

使用 URLMock

URLMock 是同时考虑到响应模拟和单元测试而设计的。二者工作方式非常相似。

响应模拟

使用 URLMock 进行响应模拟非常简单。

首先,启用 URLMock。

[UMKMockURLProtocol enable];

如果您正在使用 NSURLSession 而不是共享会话,还需要将 UMKMockURLProtocol 添加到会话配置允许可用协议类集合中。

NSURLSessionConfiguration *configuration = …;
configuration.protocolClasses = @[ [UMKMockURLProtocol class] ];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];

接下来,添加一个预期的模拟请求和响应。

// The request is a POST with some JSON data
NSURL *URL = [NSURL URLWithString:@"http://host.com/api/v1/person"];
id requestJSON = @{ @"person" : @{ @"name" : @"John Doe",
                                   @"age" : @47 } };
id responseJSON = @{ @"person" : @{ @"id" : @1,
                                    @"name" : @"John Doe",
                                    @"age" : @47 } };

[UMKMockURLProtocol expectMockHTTPPostRequestWithURL:URL
                                         requestJSON:requestJSON
                                  responseStatusCode:200
                                        responseJSON:responseJSON];

模拟请求和响应不限于 JSON 体内容;它们还可以有字符串体、WWW 表单编码参数字典或任意 NSData 实例的体。此外,还有用于返回错误或以延迟的方式返回数据块的模拟响应器,我们将在未来添加更多响应器。

当执行实际请求时,您将收到模拟响应。在使用 URLMock 时,您不需要更改代码。事情应该会如常进行。例如,以下 URLConnection 代码将接收上面的模拟响应

NSURL *URL = [NSURL URLWithString:@"http://host.com/api/v1/person"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
request.HTTPMethod = @"POST";
id bodyJSON = @{ @"person" : @{ @"name" : @"John Doe", @"age" : @47 } };
request.HTTPBody = [NSJSONSerialization dataWithJSONObject:bodyJSON
                                                   options:0
                                                     error:NULL];

// Create the connection as usual
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:…];

以下 AFNetworking 代码可以达到相同的效果

NSURL *base = [NSURL URLWithString:@"http://host.com/api/v1/"];
id params = @{ @"person" : @{ @"name" : @"John Doe", @"age" : @47 } };

// Send a POST as usual
AFHTTPRequestOperationManager *om = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:base];
om.requestSerializer = [AFJSONRequestSerializer serializer];
[om POST:@"person" parameters:params success:^(AFHTTPRequestOperation *op, id object) {
    …
} failure:^(AFHTTPRequestOperation *op, NSError *error) {
    …
}];

模式匹配模拟请求

您还可以使用UMKPatternMatchingMockRequest创建一个对匹配的请求动态响应的模拟请求。要创建模式匹配模拟请求,您需要提供一个URL模式,例如@"http://hostname.com/:resource/:resourceID"。当URL请求匹配此模式时,模拟请求将使用其响应器生成块生成适当的响应器。

NSString *pattern = @"http://hostname.com/accounts/:accountID/followers";
UMKPatternMatchingMockRequest *mockRequest =  [[UMKPatternMatchingMockRequest alloc] initWithPattern:pattern];
mockRequest.HTTPMethods = [NSSet setWithObject:kUMKMockHTTPRequestPostMethod];

mockRequest.responderGenerationBlock = ^id<UMKMockURLResponder>(NSURLRequest *request, NSDictionary *parameters) {
    NSDictionary *requestJSON = [request umk_JSONObjectFromHTTPBody];

    // Respond with
    //   {
    //     "follower_id": «New follower’s ID»,
    //     "following_id":  «Account ID that was POSTed to»
    //   }
    UMKMockHTTPResponder *responder = [UMKMockHTTPResponder mockHTTPResponderWithStatusCode:200];
    [responder setBodyWithJSONObject:@{ @"follower_id" : requestJSON[@"follower_id"],
                                        @"following_id" : @([parameters[@"accountID"] integerValue]) }];
    return responder;
};

[UMKMockURLProtocol addExpectedMockRequest:mockRequest];

有关更多信息,请参阅UMKPatternMatchingMockRequest的文档。

单元测试

使用URLMock进行单元测试与响应存根非常相似,但您可以使用一些额外的API来简化单元测试。

首先,使用+setVerificationEnabled:UMKMockURLProtocol中启用验证。这会使系统能够跟踪是否接收到了任何意外的请求。在您的xCASETest+setUp方法中这样做是有意义的。您也可以在您的+tearDown方法中禁用验证。

+ (void)setUp
{
    [super setUp];
    [UMKMockURLProtocol enable];
    [UMKMockURLProtocol setVerificationEnabled:YES];
}


+ (void)tearDown
{
    [UMKMockURLProtocol setVerificationEnabled:NO];
    [UMKMockURLProtocol disable];
    [super tearDown];
}

在每个测试之前(或之后),调用+[UMKMockURLProtocol reset]。这将重置UMKMockURLProtocol的期望回其原始状态。它不会更改是否启用了验证。

如果您正在使用XCTest,这是在测试用例的-setUp(或-tearDown)方法中执行的理想位置。

- (void)setUp
{
   [super setUp];
   [UMKMockURLProtocol reset];
}

在执行您正在测试的代码之后,向UMKMockURLProtocol发送+verifyWithError:信息。如果没有收到意外的模拟请求并处理了所有预期的模拟请求,则它将返回YES

NSError *error = nil;
XCTAssertTrue([UMKMockURLProtocol verifyWithError:&error], @"…");

为了最严格的测试,在您的UMKMockHTTPRequest实例上启用标题检查。当启用时,模拟请求只匹配具有等效标题的URL请求。您可以通过将模拟HTTP请求的checksHeadersWhenMatching属性设置为YES或使用-initWithHTTPMethod:URL:checksHeadersWhenMatching:来启用模拟HTTP请求的标题检查。

UMKMockHTTPRequest *request = [UMKMockHTTPRequest mockHTTPGetRequestWithURL:URL];
request.checksHeadersWhenMatching = YES;

请注意,一些网络API——尤其是AFNetworking——发送了您未显式设置的标题,因此在创建模拟请求之前,您应该确定这些标题是什么。为了使事情变得更简单,您可以使用+[UMKMockHTTPRequest setDefaultHeaders:]为新的UMKMockHTTPRequest实例设置默认标题。例如,如果您正在使用AFNetworking的默认HTTP请求序列化程序,您可以使用这种方式设置默认标题

[UMKMockHTTPRequest setDefaultHeaders:[[AFHTTPRequestSerializer serializer] HTTPRequestHeaders]];

非HTTP协议

默认情况下,URLMock仅支持HTTP和HTTPS。然而,它被设计为可以与任何NSURLSession支持的URL协议一起工作。如果你正在使用自定义的方案或URL协议,并希望添加对模拟请求和响应的支持,你只需创建符合UMKMockURLRequestUMKMockURLResponder协议的类即可。查看UMKMockHTTPRequestUMKMockHTTPResponder的实现示例。

所有者

@jnjosh, @prachigauriar, @macdrevx, 和 @dfowj 目前是URLMock的所有者。在问题或提交请求中提到我们,以便询问功能、项目方向或请求代码审查。

贡献、提交bug或请求增强功能

当前的URLMock非常可用,但仍有很多可以改进的地方。如果你想帮助我们修复bug或添加功能,请提交一个pull request!

我们使用GitHub问题跟踪器来处理bug、增强功能请求和有限的客户支持,因此请为这些内容之一创建一个问题。

通常,pull request应该在合并前至少得到2个项目所有者的代码审查和👍。在某些情况下,如果需要快速审查pull request,单个所有者的批准也可以,但这应该是例外而不是规则。👍👍

许可证

所有代码均受MIT许可证的许可。您可以随意使用它。