Установите свойство readonly navigationController для UIViewController для насмешек - PullRequest
9 голосов
/ 23 декабря 2010

Я создал фиктивный UINavigationController, используя OCMock. Однако я не могу назначить его свойству navigationController объекта UIViewController, поскольку это свойство доступно только для чтения.

id mockNavController = [OCMockObject mockForClass:[UINavigationController class]];
...
myViewController.navigationController = mockNavController; // readonly!

Автор этого сообщения в блоге утверждает, что нашел решение, но не смог поделиться им.

Ответы [ 4 ]

17 голосов
/ 28 декабря 2010

Нет необходимости создавать мутатор, который позволяет вам установить свойство navigationController, так как вы можете смоделировать метод доступа, который его возвращает.Вот как я это делаю:

-(void)testTappingSettingsButtonShouldDisplaySettings {
    MyController *myController = [[MyController alloc] init];

    // expect the nav controller to push a settings controller
    id mockNavigationController = [OCMockObject mockForClass:[UINavigationController class]];
    [[mockNavigationController expect] pushViewController:[OCMArg any] animated:YES];

    // set up myController to return the mocked navigation controller
    id mockController = [OCMockObject partialMockForObject:myController];
    [[[mockController expect] andReturn:mockNavigationController] navigationController];

    [myController settingsButtonTapped];

    [mockNavigationController verify];
    [mockController verify];
    [myController release];
}
2 голосов
/ 21 декабря 2013

Очень поздний ответ, но для потомков я только что обнаружил, что альтернативный способ сделать это - использовать подход, основанный на состоянии, и фактически вставить тестируемый контроллер представления в настоящий контроллер навигации. Затем вы можете нажать на свой контроллер представления и проверить, что он делает со стеком навигации, проверив состояние контроллера навигации. Вот пример:

it(@"displays the station chooser when you tap the 'Choose station' button", ^{
    // Given
    LaunchViewController *launchViewController = [LaunchViewController newWithNearestStationLocator:nil];
    [launchViewController view];
    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:launchViewController];

    // When
    [[launchViewController chooseStationBtn] sendActionsForControlEvents:UIControlEventTouchUpInside];

    // Then
    [[theValue(navController.viewControllers.count) should] equal:theValue(2)];
    [[NSStringFromClass(navController.visibleViewController.class) should] equal:@"StationsViewController"];
});
0 голосов
/ 24 декабря 2010

Существует несколько возможных решений.

Вы можете вызвать частный установщик для navigationController, но он может не существовать или работать надежно во всех случаях.

Вы можете последовать совету Дерека исоздайте категорию, которая переопределяет свойство navigationController в UIViewController.В этом случае доступ к свойству navigationController должен быть безопасным, но если UIViewController получает доступ к вспомогательному ивару напрямую в любом месте, и вы не использовали тот же самый ивар в своей категории, вы можете столкнуться с неожиданным поведением.как в http://blog.carbonfive.com/2010/03/10/testing-view-controllers/. Ваш тест не так изолирован, как вам хотелось бы в этом случае, но по крайней мере личное поведение вашего суперкласса UIViewController и UINavigationController должно быть неизменным.

0 голосов
/ 23 декабря 2010

Один из методов, который я использовал в тестах, - это определение категории, которая добавляет методы в основной класс, чтобы я мог получить доступ к внутренним свойствам. Вы можете попробовать использовать категорию для синтеза сеттера, но вам может понадобиться знать имя переменной, содержащей указатель контроллера навигации.

...