Вопрос

Я хочу протестировать фрагмент кода, который использует сеть (the NSURLConnection класс, если быть точным).Код (давайте назовем его NetworkManager) выглядит немного так:

- (id) buildConnection
{
    // some more code and then:
    return [NSURLConnection …];
}

- (void) startNetworkSync
{
    id connection = [self buildConnection];
    //…
}

В модульном тестировании я хотел бы избавиться от сети, т.е.замените NSURLConnection объект с помощью макета.Как мне это сделать?

Я попытался создать частичный макет NetworkManager это заменило бы buildConnection метод с помощью заглушки.Проблема в том, что частичные насмешки выполняются с помощью Окмок только заглушки сообщений из внешнего мира – отправка buildConnection из самого startNetworkSync вызывает исходный метод, а не заглушку.

Я также попробовал обезьянье исправление NetworkManager класс через категорию.Это работает, я могу легко переопределить buildConnection метод другим кодом и замените реальный NSURLConnection с заглушкой.Проблема в том, что я не нашел простого способа получить заглушенное соединение в тесте – соединение является закрытой частью NetworkManager.

Тогда я мог бы подклассировать NetworkManager, переопределить buildConnection метод и добавьте переменную экземпляра плюс средство доступа для созданного соединения.Тем не менее, это похоже на большой объем кода.

Как бы вы решили эту проблему?Я ищу решение, которое сохранит NetworkManager дизайн класса чистый и не требует много магии или большого количества кода в тесте.

Это было полезно?

Решение

Это именно та проблема, для решения которой предназначена инъекция зависимостей;если вы используете startNetworkSyncWithConnection:(NSURLConnection*) вместо этого вы можете легко протестировать метод с помощью фиктивного соединения.Если вы не хотите менять API для своих клиентов, вы могли бы даже сохранить startNetworkSync как оболочка, которая ничего не делает, но вызывает этот новый метод с [self buildConnection] в качестве аргумента.

Другие советы

Я модифицировал OCMock для поддержки реальных частичных макетов, см. репо на GitHub.

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

@protocol SomeNetworkService
- (NSArray*) allAvailableFoos;
- (void) insertNewFoo: (Foo*) foo;
@end

И тогда у вас будет реальная HTTP-реализация и тестовая.Это означает больше работы, но также и гораздо лучшую тестируемость.Тесты менее хрупкие и гораздо удобнее, поскольку сетевой уровень тестирования может делать все, что вам нужно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top