5

我想创建一个集成测试,它表明某个动作会导致模态视图控制器的显示。故事板设置有 2 个视图控制器,一个具有自定义 ViewController 类,第二个具有默认 UIViewController 类和标题“second”。segue 设置为具有标识符“modalsegue”的模态。在模拟器中运行应用程序效果很好,但我在定义正确的测试时遇到了很多麻烦。

视图控制器.m:

@implementation ViewController

- (IBAction)handleActionByPerformingModalSegue {
    [self performSegueWithIdentifier:@"modalsegue" sender:self];
}
@end

测试:

- (void)testActionCausesDisplayOfSecondViewController {
    ViewController * vc =
      [[UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil]   
          instantiateViewControllerWithIdentifier:@"ViewController"];

    [vc handleActionByPerformingModalSegue];
    STAssertEquals(vc.presentedViewController.title, @"second",
        @"Title of presented view controller should be second but is %@",   
        vc.presentedViewController.title, nil);
}

在以下输出中运行测试结果:

2013-06-23 17:38:44.164 SeguesRUs[15291:c07] Warning: Attempt to present <UIViewController: 0x7561370> on <ViewController: 0x7566590> whose view is not in the window hierarchy!
SeguesRUsTests.m:33: error: -[SeguesRUsTests testActionCausesDisplayOfSecondViewController] : '<00000000>' should be equal to '<9c210d07>': Title of presented view controller should be second but is (null)

我究竟做错了什么?有没有一种简单的方法可以避免第一条消息?

4

2 回答 2

1

正如错误消息指出的那样,问题在于您试图在UIViewController其视图不在UIWindow层次结构中的视图上呈现。

最简单的修复方法:

- (void)testExample {

    //
    // Arrange
    // Storyboard
    //
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];

    //
    // Arrange
    // View Controller
    //
    UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
    [UIApplication sharedApplication].keyWindow.rootViewController = viewController;

    //
    // Act
    //
    [viewController performSegueWithIdentifier:@"ModalSegue" sender:nil];

    //
    // Assert
    //
    XCTAssertEqualObjects(viewController.presentedViewController.title, @"Second");

}
于 2013-12-21T22:15:57.970 回答
0

这就是我所做的。假设我连接了带有手动触发 segue (DocumentsDetailVC) 的 DocumentsVC。下面是我的设置,然后我测试 1. segue 的存在,然后 2. 我强制视图控制器(在我的情况下我发布通知)触发其 performSegueWithIdentifier 并拦截 prepareForSegue 方法以查看是否所有新的视图控制器(DocumentsDetailVC)已设置。这包括方法调配。

我没有使用 OCHamcrest/OCMockito 进行单元测试,并且我所有的 segue 都以“Segue”添加的目标视图控制器命名([self appDelegate] segueIdentifierForClass:[SomeClass class]])。

- (void)setUp
{
  [super setUp];

  _isPad = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad;

  realPrepareForSegue = @selector(prepareForSegue:sender:);
  testPrepareForSegue = @selector(documentsBrowserTest_prepareForSegue:sender:);

  UIStoryboard *storyboard = nil;
  if (_isPad) {
    storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil];
  }
  else {
    storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPad" bundle:nil];
  }
  UINavigationController *navController = [storyboard instantiateInitialViewController];
  self.sut = (DocumentsBrowserVC *)navController.topViewController;
  [self.sut view];
}


- (void)test_DocumentsDetailsVCSegueConnected
{
  if (_isPad == FALSE) {
    STAssertNoThrow([self.sut performSegueWithIdentifier:[[self appDelegate] segueIdentifierForClass:[DocumentsDetailVC class]] sender:self], @"DocumentsDetailVC should be connected");
  }
} 


- (void)test_providerDidSelectPathLevelObject_triggersDocumentsDetailsVCSegueSectionIdFile
{
  [DocumentsBrowserTest swapInstanceMethodsForClass:[DocumentsBrowserVC class]
                                                selector:realPrepareForSegue
                                             andSelector:testPrepareForSegue];

  [[NSNotificationCenter defaultCenter] addObserver:self.sut selector:@selector(providerDidSelectPathLevelObject:) name:ProviderDidSelectPathLevelObjectNotification object:nil];

  // when    
PathLevelObject *plo = self.pathLevelObjects[SectionIdFile][4];
NSDictionary *userInfo = @{OBJECT_KEY : plo , BROWSER_AREA_KEY : @(DocumentsFolder)};
[[NSNotificationCenter defaultCenter] postNotificationName:ProviderDidSelectPathLevelObjectNotification object:nil userInfo:userInfo];

  // then
  if (_isPad == FALSE) {
    assertThat(NSStringFromClass([objc_getAssociatedObject(self.sut, storyboardSegueKey) class]), is(equalTo(@"UIStoryboardPushSegue")));
    assertThatBool([[objc_getAssociatedObject(self.sut, storyboardSegueKey) destinationViewController] isKindOfClass:[DocumentsDetailVC class]], is(equalToBool(TRUE)));
    assertThat(objc_getAssociatedObject(self.sut, senderKey), is(equalTo(self.sut)));
  }
  else {
    assertThatInteger(self.sut.detailViewController.browsingArea, is(equalToInteger(DocumentsFolder)));
    assertThat(self.sut.detailViewController.pathLevelObject, is(equalTo(plo)));
  }


  [[NSNotificationCenter defaultCenter] removeObserver:self.sut];

  [DocumentsBrowserTest swapInstanceMethodsForClass:[DocumentsBrowserVC class]
                                                selector:realPrepareForSegue
                                             andSelector:testPrepareForSegue];
}
于 2013-07-10T11:03:12.867 回答