UnitTest я должен использовать разрыв и настройку - PullRequest
1 голос
/ 06 мая 2019

Я хочу проверить такой класс:

class Foo {
    var number: Int = 0
}

В модульном тесте iOS обычно тестовый пример должен быть:

class FooTests: XCTestCase {

    var foo: Foo!

    override func setUp() {
        foo = Foo()
    }

    override func tearDown() {
        foo = nil
    }

    func testAbc() {
        print(foo.number)
        foo.number = 10
    }

    func testBCD() {
        print(foo.number)
    }

}

Тогда как насчет

class FooTests: XCTestCase {

     let foo = Foo()

     func testAbc() {
        print(foo.number)
        foo.number = 10
    }

    func testBCD() {
        print(foo.number)
    }

}

Я вижу, что все выходные данные равны 0, что означает, что при каждом запуске теста foo снова инициализируется. Так же, как использовать setUp и tearDown.

Оба пути одинаковы?

EDIT : Благодаря ответу @Anton, я даже тестировал без setUp, но с tearDown, то же самое, что и setUp и tearDown.

    var foo: Foo! = Foo()

    override func tearDown() {
        foo = nil
    }

Ответы [ 2 ]

1 голос
/ 08 мая 2019

Обратите внимание, что

var foo: Foo! = Foo()

override func tearDown() {
    foo = nil
}

все еще неверно. Проблема в том, что Foo будет создан при создании экземпляра теста. Все тесты создаются сразу. Таким образом, если в этом наборе 5 тестовых случаев, это означает, что будет 5 экземпляров FooTests, каждый со своим собственным Foo. И все до запуска каких-либо тестов.

Это может вызвать проблемы, особенно если Foo регистрируется на общем контроллере, таком как NotificationCenter.

Вместо этого сделайте

private var foo: Foo!

override func setUp() {
    super.setUp()
    foo = Foo()
}

override func tearDown() {
    foo = nil
    super.tearDown()
}

Это гарантирует, что foo будет создан в контексте работающего тестового примера.

Вы можете найти исследование этого вопроса в Большинство быстрых людей ошибаются в XCTestCase tearDown… . Это будет подробно описано в главе 2 моей будущей книги Модульное тестирование iOS на примере: советы и методики XCTest с использованием Swift .

1 голос
/ 06 мая 2019

Они ведут себя одинаково, но имеют разницу. Чтобы понять разницу, вы можете добавить в свой тестовый класс методы init и deinit:

class Foo {
    var number: Int = 0

    init() {
        print("Init")
    }

    deinit {
        print("Deinit")
    }
}

Теперь вы увидите, что в первом случае init и deinit запускаются при каждом тесте. Потому что setUp и tearDown являются методом экземпляра и вызывают до и после запуска теста.

Но во втором случае init вызывается дважды во время создания тестового набора. Это происходит потому, что вы используете инициализатор по умолчанию для константы foo. Он вызывается во время инициализации тестового примера, который происходит до запуска любого теста.

Итак, лучше использовать первый вариант. Потому что, если тестируемый экземпляр использует какое-либо глобальное состояние или имеет побочные эффекты, вы можете получить нестабильные тесты. Они живут в памяти параллельно.

Diagram

...