XCTestCase UIB кнопки - PullRequest
       14

XCTestCase UIB кнопки

0 голосов
/ 23 октября 2019

Я пытаюсь провести модульное тестирование подключения нажатий кнопок в UIViewController, но я считаю, что эти тесты не выполняются, хотя код в работающем приложении работает нормально.

Я упростил неудачный тест, удалив контроллер вида и оставив просто:

import XCTest

class ButtonTest: XCTestCase {

    var gotTap: XCTestExpectation!

    func test_givenButtonWithTargetForTapAction_whenButtonIsSentTapAction_thenTargetIsCalled() {

        gotTap = expectation(description: "Button tap recieved")

        let button = UIButton()
        button.addTarget(self, action: #selector(tap), for: .touchUpInside)

        button.sendActions(for: .touchUpInside)

        // Fails.
        wait(for: [gotTap], timeout: 0.1)
    }

    @objc func tap() {
        gotTap.fulfill()
    }
}

Тест выполняет:

  • Подключает действиек кнопке, которая соответствует ожидаемому тесту
  • Нажмите кнопку, используя button.sendActions(for: .touchUpInside)
  • Ожидает ожидания.

Ошибка:

Асинхронное ожидание не выполнено: Превышено время ожидания в 0,1 секунды с невыполненными ожиданиями: «Нажатие на кнопку получено».

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

Вопросы

  • Это сбой, потому что отправка действия UIButton требует дополнительной настройки цепочки респондента? Или цикл выполнения, которого здесь нет? Или что-то другое? Как я могу настроить это минимально в модульном тесте без создания экземпляра полностью запущенного приложения?
  • Сначала я попытался синхронно протестировать нажатия кнопок без ожидания (это также не сработало, поэтому я решил попробовать асинхронно) - если вы можете помочь в этом, укажите также, является ли отправка действия синхронной или асинхронной.

1 Ответ

0 голосов
/ 23 октября 2019

A вопрос о событиях управления имеет ответ , что для событий управления требуется экземпляр UIApplication для отправки действий. К сожалению, вопрос не указывает, как это можно сделать.

Здесь также есть код , который использует swizzling для исправления реализации отправки действия на UIControl, чтобы он неделегат UIApplication. Он не строится с недавним быстрым использованием, потому что он опирается на переопределение initialize - однако это может быть исправлено.

Я выбрал подход к реализации расширения на UIControl для использования в тестах, которыепредоставляет метод simulateEvent(_ event: UIControl.Event), который выглядит следующим образом:

extension UIControl {

    func simulateEvent(_ event: UIControl.Event) {
        for target in allTargets {
            let target = target as NSObjectProtocol
            for actionName in actions(forTarget: target, forControlEvent: event) ?? [] {
                let selector = Selector(actionName)
                target.perform(selector)
            }
        }
    }
}

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

...