2013-06-23 12 views
5

Chcę utworzyć test integracji, który pokazuje, że określone działanie powoduje wyświetlenie kontrolera widoku modalnego. Scenorys jest skonfigurowany z 2 kontrolerami widoku, jednym z niestandardową klasą ViewController, z drugą z domyślną klasą UIViewController i tytułem "second". Segue jest skonfigurowany jako modalny z identyfikatorem "modalsegue". Uruchamianie aplikacji w symulatorze działa znakomicie, ale mam wiele problemów z określeniem poprawnego testu.Automatyczne testowanie kostek

ViewController.m:

@implementation ViewController 

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

Test:

- (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); 
} 

Running wyniki testu w następujący wynik:

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) 

Co robię źle? Czy istnieje prosty sposób na uniknięcie pierwszej wiadomości?

+0

dobrze, powinieneś przejść do ram wyższym poziomie, który faktycznie UI Test a nie jakieś wewnętrzne metody - na przykład Apple UI Automation Franka-ogórka. – Sulthan

Odpowiedz

0

Oto, co robię. Założono, że mam dokument DocumentsVC z ręcznie wywołanym segue (DocumentsDetailVC) podłączony. Poniżej znajduje się moja konfiguracja, a następnie testuję 1. obecność segue, a następnie 2. Wymuszam kontroler widoku (w moim przypadku umieszczam powiadomienie), aby wywołać jego performSegueWithIdentifier i przechwycić metodę prepareForSegue, aby sprawdzić, czy wszystko dla skonfigurowano nowy kontroler widoku (DocumentsDetailVC). Obejmuje to metodę swizzling.

Nie używam OCHamcrest/OCMockito do testowania jednostkowego i że wszystkie moje nazwy są nazwane po dodaniu kontrolera widoku docelowego przez "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]; 
} 
+0

To dużo kodu testowego do weryfikacji stosunkowo niewiele. Powiedziałbyś, że masz duży majątek z takiego testu? – fatuhoku

1

Jak zaznacza komunikat o błędzie, problem jest to, że starasz się przedstawić na UIViewController którego widok nie jest w hierarchii UIWindow.

Najprostszym sposobem, aby to naprawić:

- (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"); 

} 
+0

Czy "[UIApplication sharedApplication]" nie zainicjuje wystąpienia UIApplication w teście jednostki? Co tu się dzieje? – fatuhoku

+0

Używam współużytkowanej instancji 'UIApplication', aby uzyskać dostęp do' keyWindow', dzięki czemu mogę ustawić jego 'rootViewController'. –

Powiązane problemy