Как заглушить / внедрить контроллер представления для тестирования на основе состояния во время выполнения iOS 5? - PullRequest
2 голосов
/ 18 марта 2012

Я ищу способ "наилучшей практики" / "с низким трением" для тестирования состояния на контроллерах представления внутри моего базового класса AppDelegate. В настоящее время ниже приведен простой способ заглушки в моем собственном UIViewController (с использованием ocmock), когда что-то происходит с ним внутри метода класса.

-(FirstViewController *)getFirstViewController
{
    if (self.viewController1)
    { return self.viewController1; }

    self.viewController1 = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil];

    return self.viewController1;
}

Первый вопрос, который у меня возникает - это правильный способ заглушить / ввести мой собственный контроллер макета для тестирования? (кажется, работает отлично, но я не уверен, что именно так профессионалы сегодня проводят тестирование на основе состояния)

Следующий вопрос, который у меня возникает, - действительно ли в памяти 1 копия контроллера представления в таком виде (можно создать ее с нуля только один раз на всю жизнь приложения)?

** примечание: я бы добавил это в зависимость, но мой init уже достаточно велик, просто вставляю контроллер nav и контроллер панели вкладок, так что это не вариант для этого большого класса

Ответы [ 3 ]

1 голос
/ 23 марта 2012

Если это корневой контроллер представления, вы должны просто сделать его свойством делегата приложения:

@interface MyAppDelegate : NSObject <UIApplicationDelegate>
@property(retain)FirstViewController *firstViewController;
@end

@implementation MyAppDelegate
@synthesize firstViewController;
...
@end

Если метод, который вы тестируете, не является методом, где вы инициализируете firstViewController, выне нужен какой-либо подход ленивой загрузки.Вы просто получаете делегат приложения в своем тесте, создаете экземпляр FirstViewController и назначаете его свойству для своего делегата, и определяете тест:

-(void)testSomething {
    MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    FirstViewController *firstViewController = [[FirstViewController alloc] init];
    appDelegate.firstViewController = firstViewController;

    // test some app delegate method
    ...
}

Если вы хотите макетировать контроллер длячто бы вы ни тестировали, вы также можете сделать это:

-(void)testSomething {
    MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    id mockController = [OCMockObject mockForClass:[FirstViewController class]];
    appDelegate.firstViewController = mockController;

    [[mockController expect] someControllerMethod];

    // test some app delegate method
    ...

    [mockController verify];
}
1 голос
/ 18 марта 2012

Внедрение зависимостей не требует, чтобы вы вводили все зависимости через метод init. Есть причины, почему это предпочтительнее, но это другое обсуждение.

Вы можете просто добавить -setFirstViewController: метод к вашему классу. Вы использовали бы этот метод в своем тесте, чтобы ввести свой макет. Если вам не нравится, что этот метод присутствует в вашем приложении, вы можете добавить метод, используя категорию в своем тестовом коде.

0 голосов
/ 21 марта 2012

Для такого рода испытаний я сделаю так, как ты, ну, немного по-другому.

1-я ленивая загрузка контроллера First View инкапсулирована внутри свойства.

В .h файле

@interface AppDelegate {
    FirstViewController *viewController1_;
}

Тогда

@property (nonatomic, readonly) FirstViewController viewController1;

В .m файле

- (FirstViewController *)viewController1 {
    if (!viewController1_) {
        viewController1_ = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil];
    }

    return viewController1_;
}

2nd- Если я хочу ввести фиктивный объект, я использую KVC в своем тестовом коде

[appDelegateUnderTest setValue:mockViewController forKey:@"viewController1_"];

С уважением,

...