6

Chcę przetestować UICollectionView, który znajduje się wewnątrz kontrolera UIViewController (np. Chcę przetestować, że UICollectionView ma liczbę komórek, które oczekuję, że ma w moim test jednostkowy)Jak testować UICollectionView w ramach UIViewController

Moja próba jednostka opiera się na następującym blogu (o tym, jak jednostka testowa kontroler widoku): http://yetanotherdevelopersblog.blogspot.co.il/2012/03/how-to-test-storyboard-ios-view.html

w badanej jednostki jestem w stanie uzyskać wskaźnik do UICollectionView w UIViewController której jestem testowanie. Oto kod w metodzie setup mojego testu za:

storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil]; 
viewController = [self.storyboard instantiateViewControllerWithIdentifier:@"MainViewController"]; 
[viewController performSelectorOnMainThread:@selector(loadView) withObject:nil waitUntilDone:YES]; 
self.collectionView = viewController.collectionView 

Niestety, nie ma komórki w tym UICollectionView (tj self.collectionView.visibleCells.count równa 0, a więc nie mogę uzyskać dostęp do komórek i test, który dane jest to, co ja spodziewałem się, be), chociaż podczas debugowania widzę, że moja aplikacja dodaje te komórki do widoku kolekcji.

Co robię źle? Wszelkie wskazówki & wskazówki dotyczące testowania jednostki UICollectionView w ramach kontrolera UIViewController?

Edytuj: Po pomocy Roshana mogę teraz zawęzić mój problem. Jestem jednostką testującą UIViewController, który ma UICollectionView. W moim teście jednostkowym chcę przetestować, że wartości komórek wewnątrz CollectionView są tym, czego się spodziewam. Ale collectionView:cellForItemAtIndexPath: nie jest wywoływany na moim ViewController i dlatego moje komórki nie istnieje, gdy jest to wywoływane jako test jednostkowy. Dowolny pomysł?

Odpowiedz

2

Nie wiem dokładnie, gdzie jest problem, ale dokumentacji Apple mówi to o loadView:

Nigdy nie należy wywołać tej metody bezpośrednio. Kontroler widoku wywołuje tę metodę, gdy właściwość widoku jest żądana, ale jest obecnie zerowa. Jeśli tworzysz swoje widoki ręcznie, musisz zastąpić tę metodę i użyć jej do utworzenia widoków. Jeśli korzystasz z Kreatora interfejsów do tworzenia widoków i inicjowania kontrolera widoku - to znaczy, zainicjuj widok za pomocą metody initWithNibName: bundle:, ustaw właściwości nibName i nibBundle bezpośrednio lub utwórz zarówno widoki, jak i kontroler widoku w narzędziu Konstruktor interfejsów - wtedy nie możesz przesłonić tej metody.

Zamiast wywoływać je bezpośrednio, należy wywołać [viewController view], aby wymusić załadowanie widoku.

Co do problemu, sprawdź, czy viewController.collectionView ma wartość 0, czy nie. Możliwe, że Twoje gniazdo nie zostało jeszcze ustawione.

+0

Dzięki! po wywołaniu "widoku" zamiast "loadView" wywoływana jest metoda "viewDidLoad". Wciąż mam problem, że metoda 'collectionView: cellForItemAtIndexPath:' nie jest wywoływana. Próbowałem wywoływać "reloadData" na collectionView, ale nadal nie jest on wywoływany. Dowolny pomysł? – nirch

+0

Czy możesz umieścić jakiś kod z 'MainViewController' związanego z tą metodą? (implementacja, gdzie dzwonisz, itp.) – Roshan

+0

Myślę, że rozumiem, dlaczego tak się dzieje. "collectionView: cellForItemAtIndexPath:" jest wywoływane tylko dla widocznych komórek. Ponieważ jest to test jednostkowy, nie mam żadnych widocznych komórek, a zatem nie jest on wywoływany. Myślę więc, że nie można tego przetestować za pomocą testów jednostkowych - czy mam rację? – nirch

4

Podczas implementacji TTD w systemie iOS spróbuj nie polegać na systemie wywołującym delegata i metody źródła danych.

Powinieneś wywoływać te metody bezpośrednio z testów jednostkowych. To tylko kwestia skonfigurowania odpowiedniego środowiska dla twoich testów.

Na przykład, kiedy implementuję TDD dla UICollectionView, tworzę dwie oddzielne klasy specjalnie w celu implementacji protokołów UICollectionViewDataSource i UICollectionViewDelegate, tworząc separację problemów i mogę jednostce przetestować te klasy oddzielnie do samego kontrolera widoku, chociaż wciąż trzeba zainicjować kontroler widoku, aby ustawić hierarchię widoku.

Oto przykład, oczywiście pominięto nagłówki i inne pomniejsze fragmenty kodu.

przykład UICollectionViewDataSource

@implementation CellContentDataSource 

@synthesize someModelObjectReference = __someModelObjectReference; 

#pragma mark - UICollectionViewDataSource Protocol implementation 

- (NSInteger) collectionView:(UICollectionView *)collectionView 
    numberOfItemsInSection:(NSInteger)section 
{ 
    return __someModelObjectReference ? 
     [[__someModelObjectReference modelObjects] count] : 0; 
} 

- (UICollectionViewCell *) collectionView:(UICollectionView *)collectionView 
       cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString * const kCellReuseIdentifer = @"Cell"; 
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellReuseIdentifer forIndexPath:indexPath]; 

    ModelObject *modelObject = [__someModelObjectReference modelObjects][[indexPath item]]; 

    /* Various setter methods on your cell with the model object */ 

    return cell; 
} 
@end 

Jednostka Przykład testowy

- (void) testUICollectionViewDataSource 
{ 
    UIStoryBoard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil]; 
    MainViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"MainViewController"]; 
    [viewController view]; // Loads the view hierarchy 

    // Using OCMock to mock the returning of the model objects from the model object reference. 
    // The helper method referenced builds an array of test objects for the collection view to reference 
    id modelObjectMock = [OCMockObject mockForClass:[SomeModelObjectReference class]]; 
    [[[modelObjectMock stub] andReturn:[self buildModelObjectsForTest]] modelObjects]; 

    CellContentDataSource *dataSource = [CellContentDataSource new]; 
    dataSource.someModelObjectReference = modelObjectMock; 
    viewController.collectionView.dataSource = dataSource; 

    // Here we call the data source method directly 
    UICollectionViewCell *cell = [dataSource collectionView:viewController.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; 

    XCTAssertNotNil(cell, @"Cell should not be nil"); 
    // Assert your cells contents here based on your test model objects 
} 
+0

Możliwe jest również po prostu wywołanie funkcji * cellForItemAtIndexPath: [NSIndexPath indexPathForItem: 0 inSection: 0]]; * i pomiń implementację klasy. – OhadM

Powiązane problemy