Почему не удается выполнить внутриуровневые тесты кода, чтобы найти ресурсы пакета?
Некоторый код, который я тестирую, требует загрузки файла ресурсов. Он содержит следующую строку:
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
В приложении он работает отлично, но при запуске модульной тестовой фреймворкой pathForResource:
возвращает nil, то есть не может найти foo.txt
.
Я убедился, что foo.txt
включен в фазу Скопировать Bundle Resources сборки unit test, поэтому почему он не может найти файл?
Ответы
Ответ 1
Когда жгут unit test запускает ваш код, ваш пакет unit test НЕ основной комплект.
Несмотря на то, что вы используете тесты, а не ваше приложение, ваш пакет приложений по-прежнему является основным пакетом. (Предположительно, это предотвращает проверку кода из поиска неправильного пакета.) Таким образом, если вы добавите файл ресурсов в пакет unit test, вы не найдете его, если ищете основной пакет. Если вы замените указанную выше строку следующим образом:
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *path = [bundle pathForResource:@"foo" ofType:@"txt"];
Затем ваш код будет искать пакет, в котором находится ваш класс unit test, и все будет хорошо.
Ответ 2
Реализация Swift:
Swift 2
let testBundle = NSBundle(forClass: self.dynamicType)
let fileURL = testBundle.URLForResource("imageName", withExtension: "png")
XCTAssertNotNil(fileURL)
Свифт 3, Свифт 4
let testBundle = Bundle(for: type(of: self))
let filePath = testBundle.path(forResource: "imageName", ofType: "png")
XCTAssertNotNil(filePath)
Bundle предоставляет способы обнаружения основных и тестовых путей для вашей конфигурации:
@testable import Example
class ExampleTests: XCTestCase {
func testExample() {
let bundleMain = Bundle.main
let bundleDoingTest = Bundle(for: type(of: self ))
let bundleBeingTested = Bundle(identifier: "com.example.Example")!
print("bundleMain.bundlePath : \(bundleMain.bundlePath)")
// …/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Agents
print("bundleDoingTest.bundlePath : \(bundleDoingTest.bundlePath)")
// …/PATH/TO/Debug/ExampleTests.xctest
print("bundleBeingTested.bundlePath : \(bundleBeingTested.bundlePath)")
// …/PATH/TO/Debug/Example.app
print("bundleMain = " + bundleMain.description) // Xcode Test Agent
print("bundleDoingTest = " + bundleDoingTest.description) // Test Case Bundle
print("bundleUnderTest = " + bundleBeingTested.description) // App Bundle
В Xcode 6 | 7 | 8 | 9 путь пакета для модульного теста будет в Developer/Xcode/DerivedData
что-то вроде...
/Users/
UserName/
Library/
Developer/
Xcode/
DerivedData/
App-qwertyuiop.../
Build/
Products/
Debug-iphonesimulator/
AppTests.xctest/
foo.txt
... который отделен от стандартного (не модульного) теста пути Developer/CoreSimulator/Devices
:
/Users/
UserName/
Library/
Developer/
CoreSimulator/
Devices/
_UUID_/
data/
Containers/
Bundle/
Application/
_UUID_/
App.app/
Также обратите внимание, что исполняемый файл модульного теста по умолчанию связан с кодом приложения. Однако код модульного теста должен иметь только целевое членство только в комплекте тестов. Код приложения должен иметь только целевое членство в комплекте приложений. Во время выполнения целевой пакет модульного теста вводится в комплект приложения для выполнения.
Swift Package Manager (SPM) 4:
let testBundle = Bundle(for: type(of: self))
print("testBundle.bundlePath = \(testBundle.bundlePath) ")
Примечание. По умолчанию swift test
командной строки создает тестовый пакет MyProjectPackageTests.xctest
. Причем, swift package generate-xcodeproj
создаст MyProjectTests.xctest
тестовый пакет. Эти разные тестовые пакеты имеют разные пути. Кроме того, разные тестовые пакеты могут иметь некоторые внутренние структуры каталогов и различия в содержимом.
В любом случае .bundlePath
и .bundleURL
будут возвращать путь тестового пакета, который в данный момент выполняется на macOS. Однако Bundle
в настоящее время не реализован для Ubuntu Linux.
Кроме того, командная строка swift build
и swift test
настоящее время не предоставляют механизм копирования ресурсов.
Однако, приложив некоторые усилия, можно настроить процессы для использования менеджера пакетов Swift с ресурсами в средах macOS Xcode, macOS и Ubuntu. Один пример можно найти здесь: 004.4'2 SW Dev Swift Package Manager (SPM) с ресурсами Qref
См. Также: Использование ресурсов в модульных тестах с Swift Package Manager.
Swift Package Manager (SPM) 4.2
В Swift Package Manager PackageDescription 4.2 представлена поддержка локальных зависимостей.
Локальные зависимости - это пакеты на диске, к которым можно обращаться напрямую, используя их пути. Локальные зависимости разрешены только в корневом пакете, и они переопределяют все зависимости с тем же именем в графе пакета.
Примечание: я ожидаю, но еще не проверял, что что-то вроде следующего должно быть возможно с SPM 4.2:
// swift-tools-version:4.2
import PackageDescription
let package = Package(
name: "MyPackageTestResources",
dependencies: [
.package(path: "../test-resources"),
],
targets: [
// ...
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage", "MyPackageTestResources"]
),
]
)
Ответ 3
С быстрым Swift 3 синтаксис self.dynamicType
устарел, используйте вместо этого
let testBundle = Bundle(for: type(of: self))
let fooTxtPath = testBundle.path(forResource: "foo", ofType: "txt")
или
let fooTxtURL = testBundle.url(forResource: "foo", withExtension: "txt")
Ответ 4
Подтвердите, что ресурс добавлен в тестовую цель.
![введите описание изображения здесь]()
Ответ 5
если в вашем проекте несколько целей, вам нужно добавить ресурсы между различными целями, доступными в целевом членстве, и вам может потребоваться переключиться между различными целями, выполнив 3 шага, показанных на рисунке ниже.
![enter image description here]()
Ответ 6
Я должен был убедиться, что этот флажок General Testing был установлен ![this General Testing checkbox was set]()