在XCode单元测试中测试导航

时间:2021-02-20 03:52:41

I am trying to test UIViewControllers navigation in Unit tests, I was able to do the backend testing but to increase the coverage of tests wanted to test UIViewControllers,

我试图在单元测试中测试UIViewControllers导航,我能够进行后端测试,但是为了增加测试UIViewControllers的测试的覆盖范围,

Facing a strange issue so I have a ViewController (created manually without Storyboard) which has two buttons and clicking each of these buttons takes you another view (Pushes the new view on Navigation Controller).

面对一个奇怪的问题,所以我有一个ViewController(手动创建没有Storyboard),它有两个按钮,点击这些按钮,你会看到另一个视图(在导航控制器上推新视图)。

The initialisation is as follows in viewDidLoad

viewDidLoad中的初始化如下

// Setup the action of button
[self.button1 addTarget:self
                 action:@selector(goToView1)
       forControlEvents:UIControlEventTouchUpInside];

 [self.button2 addTarget:self
                  action:@selector(goToView2)
        forControlEvents:UIControlEventTouchUpInside];

here is my code for pushing these two views

这是我推送这两个视图的代码

- (void)goToView1 
{
    // Go to the FAQ Screen
    ViewController1 *viewController = [[ViewController1 alloc] init];
    [self.navigationController pushViewController:viewController     
                                         animated:YES];
}
- (void)goToView2
{
      // Go to the checkin screen
      ViewController2 *viewController =[[ViewController2 alloc] init];
      [self.navigationController pushViewController:viewController
                                           animated:YES];
}

In my testclass I am trying to test it like this

在我的测试类中,我试图像这样测试它

- (void)testNavigation 
{
    //Initialize the view controller and call the navigation functions
    [self.testController goToView1];

    XCTAssertTrue([self.navigationController.topViewController 
                        isKindOfClass:[ViewController1 class]], 
                        @"Did not navigate Controller 1");

    [self.navigationController popToViewController:self.testController 
                                          animated:NO];

    [self.testController goToView2];

    XCTAssertTrue([self.navigationController.topViewController 
                  isKindOfClass:[ViewController2 class]], 
                  @"Did not navigate to Controller 2");

}

So this test actually fails the reason I guess is because I am checking for the ViewController immediately after i call the PushViewcontroller with animated:YES, If I push the view controllers without Animation test passes (because the view is immediately pushed and the Assert checks out ok).

所以这个测试实际上失败的原因我想是因为我在调用带有动画的PushView控制器之后立即检查ViewController:YES,如果我推动视图控制器没有动画测试传递(因为视图被立即推送并且Assert检出好)。

So My question is, is there anyway I can put a hook some where to check if the View has been pushed before checking the Assert (I dont want to turn of the animation just for passing the test as it will kill the whole purpose) also I dont want to put any aribitary delay. Can I somehow check if the push animation has completed and view is finally on top before running the test logic?

所以我的问题是,无论如何我可以在检查Assert之前检查是否已经按下了一个钩子(我不想转动动画只是为了通过测试,因为它会杀死整个目的)我不想放任何延迟。在运行测试逻辑之前,我可以以某种方式检查推送动画是否已完成并且查看最终是否在顶部?

2 个解决方案

#1


M David is partially correct: You should wrap the 'dispatch_after' with XCTestExpectation(used with Xcode 6 and above) as follows:

M David部分正确:您应该使用XCTestExpectation(与Xcode 6及更高版本一起使用)包装'dispatch_after',如下所示:

XCTestExpectation *completionExpectation = [self expectationWithDescription:@"WaitingForWhatever"];
double delayInSeconds = 3.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, popTime * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
       XCTAssertTrue([TestClass.navigationController.topViewController isKindOfClass:[requiredClass class]],@"View Controller not pushed properly");
       [completionExpectation fulfill];
});
[self waitForExpectationsWithTimeout: delayInSeconds+2 handler:nil];

#2


dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{

       XCTAssertTrue([TestClass.navigationController.topViewController isKindOfClass:[requiredClass class]],@"View Controller not pushed properly");
    });

I am sure, this shall work for you, because this block is executed after 1 sec delay.So meanwhile your view Controller will pushed accurately and navigationConrtoller.TopViewController updated with new pushed view Controller. Other point is if you are using test class then self.navigationController is not the right choice, it must be yourCustomeObject.Navigationcontroller.

我相信,这对你有用,因为这个块在1秒延迟后执行。同时你的视图控制器将准确推送并使用新的推送视图控制器更新navigationConrtoller.TopViewController。另外一点是如果你使用的是测试类,那么self.navigationController不是正确的选择,它必须是yourCustomeObject.Navigationcontroller。

#1


M David is partially correct: You should wrap the 'dispatch_after' with XCTestExpectation(used with Xcode 6 and above) as follows:

M David部分正确:您应该使用XCTestExpectation(与Xcode 6及更高版本一起使用)包装'dispatch_after',如下所示:

XCTestExpectation *completionExpectation = [self expectationWithDescription:@"WaitingForWhatever"];
double delayInSeconds = 3.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, popTime * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
       XCTAssertTrue([TestClass.navigationController.topViewController isKindOfClass:[requiredClass class]],@"View Controller not pushed properly");
       [completionExpectation fulfill];
});
[self waitForExpectationsWithTimeout: delayInSeconds+2 handler:nil];

#2


dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{

       XCTAssertTrue([TestClass.navigationController.topViewController isKindOfClass:[requiredClass class]],@"View Controller not pushed properly");
    });

I am sure, this shall work for you, because this block is executed after 1 sec delay.So meanwhile your view Controller will pushed accurately and navigationConrtoller.TopViewController updated with new pushed view Controller. Other point is if you are using test class then self.navigationController is not the right choice, it must be yourCustomeObject.Navigationcontroller.

我相信,这对你有用,因为这个块在1秒延迟后执行。同时你的视图控制器将准确推送并使用新的推送视图控制器更新navigationConrtoller.TopViewController。另外一点是如果你使用的是测试类,那么self.navigationController不是正确的选择,它必须是yourCustomeObject.Navigationcontroller。