сбой XCTestCase с assert без продолжения выполнения теста, но без остановки других тестов

Я пытаюсь протестировать свое приложение с помощью фреймворка XCTest.

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

Я заметил, что XCTestCase имеет свойство continueAfterFailure. Однако установка значения YES приводила к тому, что неудавшийся тест продолжал выполнение строк после утверждения, а установка значения NO приводила к тому, что остальные тесты вообще не выполнялись.

Есть ли решение этой проблемы?


person Yoav Schwartz    schedule 08.01.2014    source источник


Ответы (5)


Ответ Паскаля дал мне идею добиться этого должным образом. XCTool теперь ведет себя как OCUnit, когда утверждение не выполняется: выполнение тестового примера немедленно прерывается, вызывается tearDown и запускается следующий тестовый пример.

Просто переопределите метод invokeTest в своем базовом классе (тот, который наследуется от класса XCTestCase):

- (void)invokeTest
{
    self.continueAfterFailure = NO;

    @try
    {
        [super invokeTest];
    }
    @finally
    {
        self.continueAfterFailure = YES;
    }
}

Вот и все!

person Oscar Hierro    schedule 19.11.2014
comment
Странно, но не работает в Xcode 9. Он все еще продолжает выполнение после XCTFail. - person Ben Affleck; 28.01.2018

Самый простой способ - добавить:

continueAfterFailure = false

в метод setUp (). Вот так это будет выглядеть:

Swift

override func setUp() {
    super.setUp()

    continueAfterFailure = false
}

Цель-C

 - (void)setUp {
    [super setUp];

    [self setContinueAfterFailure:NO];
}
person nCod3d    schedule 08.06.2016
comment
В Objective-C вы должны использовать NO вместо FALSE. - person Michael Ozeryansky; 26.08.2016
comment
В objC вы можете использовать TRUE / FALSE или YES / NO, это ничего не меняет, это всего лишь синтаксическая вещь. - person nCod3d; 28.08.2016
comment
Конечно, но вы также можете сказать 0 и 1, но мы этого не делаем, поскольку правильный ObjC - ДА / НЕТ. Конечно, это работает, продолжайте и используйте его, просто знайте, что я не единственный, кто это исправит. - person Michael Ozeryansky; 29.08.2016
comment
Вы также должны установить continueAfterFailure в true внутри tearDown(), иначе все тестирование будет остановлено после единственного сбоя. - person Tim Vermeulen; 22.11.2016
comment
Из документации Apple: continueAfterFailure - логическое значение, указывающее, должен продолжить работу после сбоя. Это относится только к одному тесту, а не ко всем доступным тестам в классе. - person nCod3d; 06.07.2017

Один из вариантов - проверить условие в обычном режиме, а затем выйти из строя и вернуться из теста, если оно ложно.

Что-то вроде этого:

if (!condition) {
  XCFail(@"o noes");
  return;
}

Вы можете обернуть это вспомогательным макросом, чтобы сохранить удобочитаемость.

Тестовые библиотеки BDD, такие как Kiwi, более удобны для такого рода задач, поскольку они упрощают обмен настройками между много тестов, что приводит к меньшему количеству утверждений за тест.

person Chris Devereux    schedule 08.01.2014
comment
+1 Думаю, это единственный способ, кроме репликации всех макросов XCTAssertXxx. - person trojanfoe; 11.02.2014
comment
Это не единственный способ, проверьте другие ответы, чтобы найти лучший подход. - person Oscar Hierro; 19.11.2014

Я могу использовать continueAfterFailure и позволить другим тестам выполняться с использованием этого шаблона:

self.continueAfterFailure = NO;
@try
{
    // Perform test code here
}
@finally
{
    self.continueAfterFailure = YES;
}
person Pascal Bourque    schedule 29.04.2014
comment
Спасибо за эту идею. Я использовал его, чтобы дать лучший ответ, который не требует изменения кода тестовых случаев. Проверить это. - person Oscar Hierro; 19.11.2014

В проектах Swift я использую вспомогательную функцию (определенную в общем суперклассе всех моих тестов, который сам расширяет XCTestCase):

/// Like `XCTFail(...)` but aborts the test.
func XCTAbortTest(_ message: String, 
                  file: StaticString = #file, line: UInt = #line
                 ) -> Never {
    self.continueAfterFailure = false
    XCTFail(message, file: file, line: line)
    fatalError("never reached")
}

Как следует из комментария, вызов fatalError на самом деле никогда не выполняется; XCTFail упорядоченно прерывает тест (вызывается tearDown, запускается следующий тест и т. Д.). Вызов предназначен только для того, чтобы обмануть компилятор и заставить его принять Never как возвращаемый тип, поскольку XCTFail возвращает Void (он возвращает, если continueAfterFailure == true).

Обратите внимание, что self.continueAfterFailure сбрасывается на значение по умолчанию true для каждого метода тестирования. Вы также можете сделать это явным в setUp().

person Raphael    schedule 16.05.2018
comment
Я изучил свои сбои, иногда кажется, что при запуске тестов с xcodebuild тест не останавливается на XCTFail и вылетает из бегуна при fatalError. Однако я не могу воспроизвести это через Xcode. :( Я устанавливаю continueAfterFailure = False - person yuf; 24.05.2018
comment
@yuf Интересно; Никогда не пробовал запускать тесты из CLI. Другое поведение, наверное, ошибка? : / - person Raphael; 24.05.2018