Certains codes que je suis en train de tester doivent charger un fichier de ressources. Il contient la ligne suivante:
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
Dans l'application, il fonctionne très bien, mais lorsqu'il est exécuté par la structure de test unitaire, pathForResource:
renvoie nil, ce qui signifie qu'il n'a pas pu localiser foo.txt
.
Je me suis assuré que foo.txt
est inclus dans la phase Copier les ressources du paquet build de la cible de test unitaire, alors pourquoi ne peut-il pas trouver le fichier?
Lorsque le harnais de test unitaire exécute votre code, votre lot de test unitaire estPASle lot principal.
Même si vous exécutez des tests, et non votre application, votre bundle d'applications reste le bundle principal. (Cela empêchera vraisemblablement le code que vous testez de rechercher le mauvais ensemble.) Ainsi, si vous ajoutez un fichier de ressources au groupe de tests unitaires, vous ne le trouverez pas si vous recherchez le groupe principal. Si vous remplacez la ligne ci-dessus par:
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *path = [bundle pathForResource:@"foo" ofType:@"txt"];
Ensuite, votre code recherchera le bundle dans lequel se trouve votre classe de test unitaire et tout ira bien.
Une implémentation rapide:
Swift 2
let testBundle = NSBundle(forClass: self.dynamicType)
let fileURL = testBundle.URLForResource("imageName", withExtension: "png")
XCTAssertNotNil(fileURL)
Swift 3, Swift 4
let testBundle = Bundle(for: type(of: self))
let filePath = testBundle.path(forResource: "imageName", ofType: "png")
XCTAssertNotNil(filePath)
Bundle fournit des moyens de découvrir les chemins principal et de test de votre configuration:
@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
Dans Xcode 6 | 7 | 8 | 9, un chemin d'accès au bundle unit-test sera dans Developer/Xcode/DerivedData
quelque chose comme ...
/Users/
UserName/
Library/
Developer/
Xcode/
DerivedData/
App-qwertyuiop.../
Build/
Products/
Debug-iphonesimulator/
AppTests.xctest/
foo.txt
... qui est distinct du chemin Developer/CoreSimulator/Devices
_ regular (non-unit-test):
/Users/
UserName/
Library/
Developer/
CoreSimulator/
Devices/
_UUID_/
data/
Containers/
Bundle/
Application/
_UUID_/
App.app/
Notez également que l'exécutable de test unitaire est, par défaut, lié au code de l'application. Toutefois, le code de test d'unité ne doit avoir que l'appartenance à la cible dans le lot de test. Le code de l'application doit uniquement avoir l'appartenance à la cible dans le bundle d'application. Au moment de l'exécution, le groupe de cibles de test unitaire est injecté dans le groupe d'applications pour être exécuté . _
Gestionnaire de paquets Swift (SPM) 4:
let testBundle = Bundle(for: type(of: self))
print("testBundle.bundlePath = \(testBundle.bundlePath) ")
Remarque: Par défaut, la ligne de commande Swift test
crée un ensemble de tests MyProjectPackageTests.xctest
. Et, le Swift package generate-xcodeproj
créera un ensemble de tests MyProjectTests.xctest
. Ces différents ensembles de tests ont différents chemins. De plus, les différents ensembles de tests peuvent avoir une structure de répertoire internal et des différences de contenu.
Dans les deux cas, .bundlePath
et .bundleURL
renverront le chemin du bundle de test en cours d'exécution sur macOS. Cependant, Bundle
n'est actuellement pas implémenté pour Ubuntu Linux.
De plus, les lignes de commande Swift build
et Swift test
ne fournissent pas actuellement de mécanisme de copie des ressources.
Cependant, avec quelques efforts, il est possible de configurer des processus pour utiliser Swift Package Manager avec des ressources des environnements macOS Xcode, macOS en ligne de commande et Ubuntu. Vous trouverez un exemple ici: 004.4'2 SW Dev Gestionnaire de packages (SPM) avec ressources Qref
Voir aussi: Utiliser des ressources dans les tests unitaires avec Swift Package Manager
Gestionnaire de paquets Swift (SPM) 4.2
Swift Package Manager PackageDescription 4.2 introduit le support des dépendances locales .
Les dépendances locales sont des packages sur disque qui peuvent être référencés directement à l'aide de leurs chemins. Les dépendances locales ne sont autorisées que dans le package racine et remplacent toutes les dépendances du même nom dans le graphique du package.
Remarque: j'espère, mais je n'ai pas encore testé, que SPM 4.2 devrait permettre:
// Swift-tools-version:4.2
import PackageDescription
let package = Package(
name: "MyPackageTestResources",
dependencies: [
.package(path: "../test-resources"),
],
targets: [
// ...
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage", "MyPackageTestResources"]
),
]
)
Avec Swift Swift 3, la syntaxe self.dynamicType
est obsolète, utilisez plutôt ceci
let testBundle = Bundle(for: type(of: self))
let fooTxtPath = testBundle.path(forResource: "foo", ofType: "txt")
ou
let fooTxtURL = testBundle.url(forResource: "foo", withExtension: "txt")