Как создать тест, который проходит при срабатывании функции? - PullRequest
0 голосов
/ 01 декабря 2018

Я пытаюсь выполнить модульное тестирование двух функций в классе контроллера представления.Две функции создадут пользователя и войдут в него соответственно.Мои тесты не связаны с пользовательским интерфейсом.

На данный момент мне просто нужно создать тест, который проходит при вызове одной из функций.Цель состоит в том, чтобы сделать это без изменения текущей реализации контроллера представления, если это возможно, и просто сохранить все это в классе / функции тестирования.

Как мне это сделать?

Спасибо

1 Ответ

0 голосов
/ 05 декабря 2018

Я предполагаю, что у контроллера представления есть метод, который вызывает либо «создание пользователя», либо «вход пользователя».(Вы говорите, что это не связано с пользовательским интерфейсом, но мы можем легко проверить нажатия кнопок, если это триггер.)

class MyViewController: UIViewController {
    func triggeringMethod() {
        // Calls one of the two methods below
    }

    func createUser() {
        // Does stuff
    }

    func signInUser() {
        // Does stuff
    }
}

И это звучит так, как будто вы хотите проверить поток, но не эффект.То есть вы хотите проверить "Был ли createUser() вызван?"Есть несколько способов получить то, что вы хотите, но лучшие способы потребуют от вас изменения реализации контроллера представления.

Создание частичного макета

Стандартный трюк из Эффективная работа сLegacy Code от Michael Feathers - «Метод подкласса и переопределения».Давайте начнем там.В тестовом коде мы можем сделать

class TestableMyViewController: MyViewController {
    override func createUser() {
    }

    override func signInUser() {
    }
}

Пока что это способ заглушить эффекты этих методов.Но теперь мы можем добавить методы насмешки из моей попытки!Быстрые разговоры в Токио.

class TestableMyViewController: MyViewController {
    var createUserCallCount = 0
    var signInUserCallCount = 0

    override func createUser() {
        createUserCallCount += 1
    }

    override func signInUser() {
        signInUserCallCount += 1
    }
}

Теперь вы можете вызвать метод запуска и проверить количество вызовов.

(Изменения, которые вам, возможно, придется внести: класс не может быть finalМетоды не могут быть private.)

Перемещение рабочих

Хотя это хорошее место для начала, не останавливайтесь на этом.То, что мы создали, является «частичной насмешкой».Вот где мы сохранили большую часть функциональности, но смоделировали пару методов.Это то, чего следует избегать.Причина в том, что мы получаем класс, который смешивает производственный код и тестовый код.Было бы слишком легко оказаться в ситуации, когда вы непреднамеренно тестируете тестовый код, а не тестируете производственный код.

То, что частичная имитация дает понять, что мы пропустили границу.Контроллер вида делает слишком много.Фактическая работа «создать пользователя» и «войти в систему пользователя» должна выполняться другим типом (возможно, даже 2-мя типами).В Swift мы можем определить эту границу с помощью протокола.Таким образом, производственный код может использовать реальную функциональность, в то время как для тестового кода мы можем вводить макеты.

Это означает, что производственный код должен избегать для себя решения, кто выполняет реальную работу.Вместо этого мы должны сказать , кто это делает.Таким образом, тесты могут предоставить альтернативных работников.Определение этих зависимостей извне называется «Внедрение зависимостей».

Передача обратных эффектов

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

enum Effect {
    case createUser(CreateUserRequestModel)
    case signInUser(SignInUserRequestModel)
}

Вместо вызывающего метода, вызывающего createUser() или signInUser(), он вызовет делегат.(Другой вариант - передать замыкания вместо указания делегатов.)

protocol Delegate {
    perform(_ effect: Effect)
}

Затем в методе запуска

delegate?.perform(.createUser(parameters))

Это означает, что фактический делегат должен преобразовать это перечисление.ценности в реальную работу.Но это облегчает написание тестов.Все, что нам нужно, это предоставить тестовую реализацию, которая фиксирует значение Effect.

...