【问题标题】:XCTest testing for delegate methods being calledXCTest 测试被调用的委托方法
【发布时间】:2014-07-21 05:48:25
【问题描述】:

我一直在尝试测试我创建的一些使用NSNetServer 类等执行网络操作的类。我在确保调用委托方法时遇到了一些问题。

我尝试了很多方法,包括:

使用[NSThread sleepForTimeInterval:5.0f];[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0f]]; 在其他操作发生时简单地暂停。 NSRunLoop 方法在第一次调用时有效(如下面的示例代码所示),但在第二次调用时崩溃。我明白这也不是“正确”的做事方式,但我不知道“正确”的方式是什么。

使用NSConditionNSConditionLock 类,这似乎只是锁定了代码并且从不调用回调。

在回调方法中更改的变量上使用while循环,同上。

为简单起见,下面是带有几个额外 cmets 和一些测试的代码:

- (void)testCheckCredentials
{
    [self.server start];
    // Create a client
    self.nsb = [[NSNetServiceBrowser alloc] init];
    // Set the delegate to self
    self.nsb.delegate = self;
    // Search for the server
    [self.nsb searchForServicesOfType:self.protocol inDomain:@""];
    // Wait for the service to be found and resolved
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:self.timeout]];
    XCTAssertTrue(self.serviceWasFound, @"Service was not found");
    // Open the connection to the server
    XCTAssertTrue([self.serverConnection open], @"Connection to server failed to open");
    // Wait for the client to connect
    /* This is where it crashes */
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:self.timeout]];
    XCTAssertTrue(self.clientDidConnect, @"Client did not connect");
    /* Further, more class-specific tests */
}

- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing
{
    NSLog(@"Found a service: %@ (%@)", service.name, service.domain);
    if ([self.serverName isEqualToString:service.name]) {
        self.serviceWasFound = YES;
    }
}

- (void)clientDidConnect:(RCFClientConnection *)client
{
    XCTAssertNotNil(client, @"Connected client is nil");
    self.clientConnection = client;
    self.clientDidConnect = YES;
}

我还尝试在 NSCondition 对象上执行 lock

[self.nsb searchForServicesOfType:self.protocol inDomain:@""];
// Wait for the service to be found and resolved
[self.lock lockWhenCondition:1];
XCTAssertTrue(self.serviceWasFound, @"Service was not found");

self.serviceWasFound = YES;
[self.lock unlockWithCondition:1]

使用 lock 方法时,永远不会调用 netServiceBrowser:didFindService:moreComing: 方法,我使用时也是这样:

while (!self.serviceWasFound) {};

我仍在学习 Objective-C,但我完全陷入了这个问题。

【问题讨论】:

    标签: ios objective-c macos xctest


    【解决方案1】:

    许多测试库支持测试异步和线程操作。

    它们的工作方式基本相同:

    • 等待 x 秒以使条件发生。
    • 可选择在第一个条件之后执行一组断言,如果其中一个不满足则失败。
    • 如果在指定(或默认)时间内未出现所需条件,则失败。

    以下是一些提供这些功能的库:

    • expecta 匹配库。
    • Kiwi 测试框架。
    • Typhoon DI 框架具有用于执行异步集成测试的实用程序。

    据我所知,所有这些库都使用运行循环方法,因为其他库可能会导致死锁。为了使这种方法可靠地工作:

    • 在测试基于块的回调时,您可以内联创建块。
    • 对于委托回调,您应该创建一个单独的存根(协议的最简单实现)或使用模拟(使用模拟库创建的“魔术”实现),并将其设置为委托。如果您将测试实例本身设置为委托,您可能会遇到问题。

    编辑:

    从 Xcode6 开始,有一个新的断言 XCTestExpectation 用于异步测试。

    以上每个库都可以使用CocoaPods 安装。

    【讨论】:

    • 没有必要为此使用库。 XCTest 有为此目的创建的 XCTestException。
    • @Accatyyc 你不是说XCTestExpectation吗? XCTest 是一个库。 .不过感谢您提供的信息 - 似乎是一个方便的新功能。
    • 是的,这是一个错字!这是一个图书馆。也许我应该说“第三方库”,因为 XCTest 是内置的
    • 是的,请注意上面的答案是在 Xcode 6 之前编写的,所以无论如何它都是及时的新信息
    【解决方案2】:

    为了处理调用异步执行方法和函数的测试组件,Xcode 6 中的 XCTest 已得到增强,包括使用新 API 和 XCTestExpectation 类对象处理块的能力。这些对象响应新的 XCTest 方法,这些方法允许测试方法等待异步调用返回或达到超时。

    这是上述摘录的苹果文档链接。 Writing Tests of Asynchronous Operations

    @interface sampleAPITests : XCTestCase<APIRequestClassDelegate>{
    APIRequestClass *apiRequester;
    XCTestExpectation *serverRespondExpectation;
    }
    @end
    
    //implementation test class
    - (void)testAPIConnectivity {
    // This is an example of a functional test case.
    serverRespondExpectation = [self expectationWithDescription:@"server responded"];
    [apiRequester sendAPIRequestForMethod:nil withParams:nil];//send request to server to get tap info
    apiRequester.delegate = self;
    [self waitForExpectationsWithTimeout:1 handler:^(NSError *error) {
        if (error) {
            NSLog(@"Server Timeout Error: %@", error);
        }
       nslog(@"execute here after delegate called  or timeout");
    }];
    XCTAssert(YES, @"Pass");
    }
    
    //Delegate implementation
    - (void) request:(APIRequest *)request didReceiveResponse:(NSDictionary *)jsonResponse success:(BOOL)success{
    [serverRespondExpectation fulfill];
    XCTAssertNotNil(jsonResponse,@"json object returned from server is nil");
    }
    

    【讨论】:

    • XCTestExpectation 就是为了解决这个问题而创建的。我们自己使用它,效果很好。
    • 哇,终于。谢谢你的信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 2020-11-28
    • 2017-05-04
    • 2013-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多