Cryptic NSInternalInconsistencyException при запуске модульных тестов в Xcode 9 GM
Я запускаю модульные тесты моего iOS-приложения на Xcode 9 GM, и несколько из них терпят неудачу со странным NSInternalInconsistencyException, жалуясь, что некоторые утверждения тестов не могут быть сообщены, потому что вовлеченные тесты не имеют связанного объекта XCTestRun. Я использую OCMockito + OCHamcrest для насмешек и проверки звонков.
Для демонстрации предположим, что мое приложение называется MyTestApp, и у меня есть тестовый класс FooTest (который наследуется от XCTestCase). В -установки, я создаю и соедините проволокой различные макеты объектов для испытаний, и в процессе демонтажа я установил их на ноль на всякий случай.
Вот пример исключения, которое я получаю:
2017-09-19 13:23:01.852729-0700 xctest[17006:5392130] *** Assertion failure in -[FooTest recordFailureWithDescription:inFile:atLine:expected:], /Library/Caches/com.apple.xbs/Sources/XCTest_Sim/XCTest-13201/Sources/XCTestFramework/Core/XCTestCase.m:308
/Users/fooUser/Workspaces/MyTestApp/tests/FooTest.mm:46: error: -[FooTest testSomething] : failed: caught "NSInternalInconsistencyException", "Unable to report test assertion failure 'Expected 1 matching invocation, but received 0' from /Users/fooUser/Workspaces/MyTestApp/tests/FooTest.mm:135 because it was raised inside test case -[FooTest testSomethingElse] which has no associated XCTestRun object. This may happen when test cases are constructed and invoked independently of standard XCTest infrastructure."
(
0 CoreFoundation 0x000000010255d1cb __exceptionPreprocess + 171
1 libobjc.A.dylib 0x0000000101ebff41 objc_exception_throw + 48
2 CoreFoundation 0x0000000102562362 +[NSException raise:format:arguments:] + 98
3 Foundation 0x0000000101827089 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 193
4 XCTest 0x0000000101d96875 -[XCTestCase recordFailureWithDescription:inFile:atLine:expected:] + 518
5 MyAppUnitTests 0x000000011d7f2f5a -[HCXCTestFailureReporter executeHandlingOfFailure:] + 154
6 MyAppUnitTests 0x000000011d7f2b73 -[HCTestFailureReporter handleFailure:] + 67
7 MyAppUnitTests 0x000000011d64ec9a MKTFailTest + 217
8 MyAppUnitTests 0x000000011d64c3f4 -[MKTExactTimes verifyData:] + 254
9 MyAppUnitTests 0x000000011d64f2ba -[MKTBaseMockObject verifyInvocation:usingVerificationMode:] + 137
10 MyAppUnitTests 0x000000011d64f20b -[MKTBaseMockObject handlingVerifyOfInvocation:] + 115
11 MyAppUnitTests 0x000000011d64f15a -[MKTBaseMockObject forwardInvocation:] + 64
12 CoreFoundation 0x00000001024dfed8 ___forwarding___ + 760
13 CoreFoundation 0x00000001024dfb58 _CF_forwarding_prep_0 + 120
14 MyAppUnitTests 0x000000011c40b486 -[FooTest setUp] + 294
15 XCTest 0x0000000101d97b39 __24-[XCTestCase invokeTest]_block_invoke_3 + 31
16 XCTest 0x0000000101d97809 __24-[XCTestCase invokeTest]_block_invoke + 271
17 XCTest 0x0000000101ddff45 -[XCUITestContext performInScope:] + 183
18 XCTest 0x0000000101d976ef -[XCTestCase invokeTest] + 141
Несколько примечательных моментов:
- Модульные тесты не инициализируют xctestcase или любые классы "инфраструктуры" XCTest вне рамок XCTest.
- остальные операторы затронутых модульных тестов фактически выполняются, вплоть до момента исключения.
- В причастная строка кода выглядит следующим образом:
[verify(_mockTestObject) description]; - трассировка стека лежит там, где возникает проблема - она говорит, что она находится в настройке, но из того, что я могу сказать, OCMockito просто сообщает о сбоях ожидания в началеследующего запуска модульного теста. Проблемное место (FooTest. mm: 135) выглядит так же, как и приведенный выше вызов verify ().
На самом деле, все модульные тесты, которые терпят неудачу с этим исключением, терпят неудачу, потому что мы пытаемся проверить, что -[NSObject description] был вызван на одном макете объект или другой. Удаление всех экземпляров проверки этого вызова делает тесты проходными.
Есть идеи, где я должен искать дальше? Большое спасибо!
1 ответ:
Я столкнулся с подобной проблемой во время работы над большим набором тестов устаревшего кода. Вопрос в том, хорошо ли работают ваши тесты с
XCTExpectation, когда вы запускаете их отдельно? Если это так, это означает, что некоторые тесты, выполняемые перед вашими тестами сNSInternalInconsistencyException, отправляютXCTestсвязанные методы таким образом, что они выполняются после завершения соответствующего теста.Это выглядит так (пример):
Test1 - > отправляет асинхронно "блок", который выполняет
XCTFailTest1 - > finishes
XCTFailвыполняется (но Test1 проходит, так как он закончился без "fail") на основном или другом потоке.Test2 - > проверяет что-то с помощью
XCTExpectation->NSInternalInconsistencyExceptionДокументы Apple не предоставляют много информации о внутренних внутренностях XCTest, но я уверен, что это проблема. Попробуйте выполнить следующие шаги по устранению неполадок, чтобы определить тесты "конфликтующие" (плохие, которые делают асинхронные вещи без XCTestExpectation, например, использовать методы с обработчики завершения, которые в конечном счете делают утверждения
XCTest, терпят неудачу и т. д.):
- выполните двоичный поиск в вашем наборе: отключите половину тестов и запустите набор с вашим
FooTest.- Если ваш набор тестов работает нормально, повторно включите половину отключенных тестов. Если набор тестов выполняется с исключением, повторно включите все отключенные тесты и отключите другую половину.
- затем повторите шаг 1 относительно меньшего количества оставшихся тестов.
- В конце концов вы получите тесты, которые вызывают это исключение.
В моем случае было несколько тестов, вызывающих этот конфликт с
Затем тщательно исследуйте, что происходит в тесте, который противоречит вашему тесту.XCTestExpectation, поэтому поиск был довольно утомительным (несколько часов для набора из 1000+XCTestCases, так что около 5K тестов).