Как расширения XCTestCase, вызываемые из вспомогательного метода, могут узнать, какие свойства были установлены в основном тестовом примере?

#swift #xctest #xcode-ui-testing #xctestcase #xctestexpectation

#swift #xctest #xcode-ui-testing #xctestcase #xctestexpectation

Вопрос:

Предыстория

Следующие тесты вызывают метод, который является расширением XCTestCase. Цель:

  • waitForElementExists Метод возвращает, потому что элемент существует или
  • waitForElementExists Метод завершает работу с ошибкой вызвавшего его тестового примера / метода установки, поскольку элемент не существовал в течение указанного времени

Расширение XCTestCase для автоматизации пользовательского интерфейса для ожидания метода:

 extension XCTestCase
{
    /**
    Wait for the view to load
    Note: Must be a part of XCTestCase in order to utilize expectationForPredicate and waitForExpectationsWithTimeout

    - Parameter
    - element:    The XCUIElement representing the view
    - timeout: The NSTimeInterval for how long you want to wait for the view to be loaded
    - file: The file where this method was called
    - line: The line where this method was called
    */
    func waitForElementExists(element: XCUIElement, timeout: NSTimeInterval = 60,
                       file: String = #file, line: UInt = #line)
    {
        let exists = NSPredicate(format: "exists == true")

        expectationForPredicate(exists, evaluatedWithObject: element, handler: nil)
        waitForExpectationsWithTimeout(timeout) { (error) -> Void in
            if (error != nil)
            {
                let message = "Failed to find (element) after (timeout) seconds."
                self.recordFailureWithDescription(message,
                                                  inFile: file, atLine: line, expected: true)
            }
        }
    }
}
  

Пример, в котором waitForExpectationsWithTimeout работает правильно

Тестовый пример

 override func setUp()
{
    super.setUp()

    // Stop immediately when a failure occurs.
    continueAfterFailure = false

    XCUIApplication().launch()

    waitForElementExists(XCUIApplication().buttons["Foo"])
}

func testSample()
{
    print("Success")
}
  

Это работает! testSample никогда не вызывается.

Но что, если мы переместим вызов waitForElementExists во вспомогательный метод?

Пример, в котором waitForExpectationsWithTimeout возвращается успешно, но не должен

Здесь тестовый пример продолжается, как будто утверждение никогда не выполнялось. Если я ввожу точку останова в waitForElementExists , я вижу, что continueAfterFailure для нее установлено значение true, поэтому ясно, что она не подключена к тому же коду, что и основной тестовый пример.

Тестовый пример

 lazy var SomeHelper = SomeHelperClass()

override func setUp()
{
    super.setUp()

    // Stop immediately when a failure occurs.
    continueAfterFailure = false

    XCUIApplication().launch()

    SomeHelper.waitForReady()

}

func testSample()
{
    print("Success")
}
  

Вспомогательный файл

 class SomeHelperClass: XCTestCase
{
    /**
    Wait for the button to be loaded
    */
    func waitForReady()
    {
        waitForElementExists(XCUIApplication().buttons["Foo"])
    }
}
  

Ответ №1:

Поскольку ваш вспомогательный класс относится к подклассам XCTestCase, у него есть собственное continueAfterFailure свойство, которое по умолчанию равно true.

Если вам нужен вспомогательный класс, он не должен происходить от XCTestCase, поскольку подклассы XCTestCase должны реализовывать методы тестирования. Если вам нужно получить доступ к функциональности из вашего расширения XCTestCase в вашем вспомогательном классе, передайте объект вашего тестового примера по композиции при создании вашего вспомогательного класса.

 class SomeHelper {

  let testCase: XCTestCase

  init(for testCase: XCTestCase) {
    self.testCase = testCase
  }

  func await(_ element: XCUIElement) {
    testCase.waitForElementExists(element)
  }

}

class MyTests: XCTestCase {

  let app = XCUIApplication()
  var helper: SomeHelper!

  func setUp() {
    continueAfterFailure = false
    helper = SomeHelper(for: self)
    helper.await(app.buttons["foo"])
  }

}