Тесты функций с KIF: beforeEach вызывается после загрузки моего контроллера представления?

У меня простой (наверное) вопрос.

Я хочу протестировать возможности своего приложения с помощью Specta и KIF. Проблема в том, что я устанавливаю зависимость в методе viewDidLoad моего контроллера представления, а в методе beforeEach моей спецификации я ввожу поддельный объект только для того, чтобы не попасть в сеть.

Результат неверный, потому что viewDidLoad вызывается перед методом beforeEach в спецификациях.

Есть ли возможность установить зависимости до того, как AppDelegate загрузит контроллер корневого представления, чтобы все было правильно настроено?


person Konrad Szczęśniak    schedule 13.02.2015    source источник


Ответы (1)


Тесты, которые зависят от цели (например, KIF и некоторые модульные тесты), запускаются после запуска приложения, поэтому нет, вы не можете заставить beforeEach идти перед вашим AppDelegate без какого-либо ужасного хакерства.

Я не знаю, как вы делаете внедрение зависимостей, поэтому вот как мы это делаем/некоторые общие стратегии.

В идеале тесты KIF не должны имитировать уровень кода

Это связано с тем, что KIF является своего рода альтернативой UIAutomation и в основном полезен для функциональных/функциональных тестов на уровне пользовательского интерфейса. Вы действительно не хотите так сильно менять код своего приложения. Мок лучше всего достигается с помощью фреймворков, таких как OHHTTPStubs для сети или OCMock для объектов, и они лучше всего работают, когда ограничены модульными тестами.

Как имитировать сетевые запросы в «настоящем» приложении

Лучший способ здесь — использовать что-то вроде OHHTTPStubs или сервера AMY (созданного теми же людьми, что и KIF) или Nocilla для возврата ответов-заглушек. Таким образом, вы можете позволить вашему коду приложения работать полностью. OHHTTPStubs, например, использует NSURLProtocol для перехвата ваших запросов, поэтому с точки зрения приложения это почти так же хорошо, как выход в сеть.

Я действительно хочу смоделировать эти объекты

Если вы действительно действительно хотите смоделировать объекты, внедренные зависимостями, с разными объектами, то есть несколько более и менее хакерских вариантов.

1) Используйте реальную структуру DI (или создайте свою собственную), которая позволяет исправлять зависимости. Я использовал Тайфун, и это разумно. Стандартная идея здесь — использовать инверсию управления в своих интересах. Поскольку вы получаете все свои объекты из контекста приложения, а не напрямую, гораздо проще настроить уровень абстракции контекста приложения. У Typhoon даже есть вики-страница на эту тему: https://github.com/appsquickly/Typhoon/wiki/Integration-Testing

2) Отследите источник объекта, который вы вводите, и хотите смоделировать и изменить его в источнике. Это не самое элегантное решение, и вы все равно как бы взламываете инфраструктуру DI, но, возможно, у вас недостаточно времени или сложности, чтобы оправдать переход на инфраструктуру DI.

3) Взломайте все до верхнего уровня. Имейте тестовый AppDelegate, который является подклассом вашего обычного AppDelegate, и используйте его во время тестирования KIF (и, конечно же, заглушайте или имитируйте объекты, которые вы хотите). Это не гибко, но опять же, может быть, вам просто нужен один тестовый пример или что-то в этом роде:

int main(int argc, char *argv[])
{
    int returnValue;
    @autoreleasepool {
        BOOL inIntegrationTests = NSClassFromString(@"KIFTestCase") != nil;
        if (inIntegrationTests) {
            returnValue = UIApplicationMain(argc, argv, nil, @"AppDelegateForTest");
        }
        else {
            returnValue = UIApplicationMain(argc, argv, nil, @"AppDelegate");
        }
    }
    return returnValue;
}

В конечном счете, к сожалению, это не простой вопрос «куда мне поставить этот метод».

person plluke    schedule 17.02.2015
comment
Спасибо за ваш обширный ответ. Нам придется смоделировать некоторые объекты, так как мы хотим запустить функциональные тесты на Travis. Помимо заглушки HTTP-запросов, нам нужно сделать то же самое для других вещей, например. Служба определения местоположения. Я также назначил награду за этот связанный вопрос. - person MaciejGórski; 18.02.2015
comment
@ MaciejGórski Я тоже ответил на этот вопрос. Дал два подхода, так как не был уверен в качестве службы определения местоположения. Если это CLLocationManager, то первый шаблон будет работать нормально. Если это какая-то другая служба определения местоположения с синглтоном, вам нужно немного поизобретать и использовать второй метод. Я бы настоятельно рекомендовал что-то вроде Typhoon, поскольку он идеально подходит для такого случая (необходимость имитировать вещи во время интеграционного тестирования). - person plluke; 19.02.2015
comment
@KonradSzczęśniak Спасибо! Рад, что смог помочь. - person plluke; 19.02.2015
comment
@plluke Это работает и для вас в бета-версии Xcode 7? Я использую аналогичную вещь для модульного тестирования, но в Xcode 7 beta 6 тестовый делегат не найден, и тестовая цель вылетает. - person AShavit; 01.09.2015
comment
Извините, если это не совсем связано, но ответ plluke помог мне исправить мою конфигурацию KIF, поэтому я подумал, что смогу кому-то помочь. Я столкнулся с этой проблемой здесь: stackoverflow.com/questions/18538958/, где в основном KIF не может найти ключевое окно для приложения (и выдает не слишком полезное исключение из-за этого). Если вы заменяете экземпляры AppDelegate на основе тестовой среды, как это делает plluke выше, возможно, вы даете KIF конфигурацию AppDelegate, которая не создает надлежащее ключевое окно. - person Brian Sachetta; 31.08.2018