Pourquoi les codes de tests unitaires ne peuvent-ils pas trouver des ressources de bundle?

Certains tests de code que je teste à l’unité doivent charger un fichier de ressources. Il contient la ligne suivante:

NSSsortingng *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"]; 

Dans l’application, elle fonctionne pathForResource: , mais lorsqu’elle est exécutée par le framework de test d’unité, pathForResource: retourne nil, ce qui signifie qu’elle ne peut pas localiser foo.txt .

Je me suis assuré que foo.txt est inclus dans la phase de génération des ressources du groupe de copies de la cible de test unitaire, alors pourquoi ne peut-il pas trouver le fichier?

Related of "Pourquoi les codes de tests unitaires ne peuvent-ils pas trouver des ressources de bundle?"

Lorsque le faisceau de test de l’unité exécute votre code, votre kit de test d’unité N’EST PAS le kit principal.

Même si vous exécutez des tests et non votre application, votre bundle d’applications rest le kit principal. (Cela supprime probablement que le code que vous testez ne recherche pas 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 fichier principal. Si vous remplacez la ligne ci-dessus par:

 NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSSsortingng *path = [bundle pathForResource:@"foo" ofType:@"txt"]; 

Ensuite, votre code recherchera le paquet dans lequel se trouve votre classe de test unitaire et tout ira bien.

Une mise en œuvre 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 permet de découvrir les chemins principaux 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 de paquet de test unitaire 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 Developer/CoreSimulator/Devices standard (non-unit-test) Developer/CoreSimulator/Devices :

 /Users/ UserName/ Library/ Developer/ CoreSimulator/ Devices/ _UUID_/ data/ Containers/ Bundle/ Application/ _UUID_/ App.app/ 

Notez également que l’exécutable de test d’unité est, par défaut, lié au code de l’application. Cependant, le code de test d’unité ne doit comporter que l’appartenance à la cible uniquement dans le groupe de tests. Le code de l’application ne doit comporter que l’appartenance à la cible dans le lot d’applications. Lors de l’exécution, le groupe cible de test unitaire est injecté dans le groupe d’applications pour exécution .

Swift Package Manager (SPM) 4:

 let testBundle = Bundle(for: type(of: self)) print("testBundle.bundlePath = \(testBundle.bundlePath) ") 

Remarque: Par défaut, le swift test ligne de commande crée un ensemble de tests MyProjectPackageTests.xctest . Et, le swift package generate-xcodeproj créera un bundle de test MyProjectTests.xctest . Ces différents ensembles de tests ont des chemins différents . En outre, les différents ensembles de tests peuvent présenter des différences de structure et de contenu internes .

Dans les deux cas, les .bundlePath et .bundleURL le chemin du paquet de test actuellement exécuté sur macOS. Cependant, Bundle n’est pas actuellement implémenté pour Ubuntu Linux.

En outre, swift build et le swift test swift build ligne de commande ne constituent pas actuellement un mécanisme de copie des ressources.

Cependant, avec un certain effort, il est possible de configurer des processus pour utiliser le gestionnaire de paquets Swift avec des ressources dans les environnements de ligne de commande macOS Xcode, macOS et Ubuntu. Un exemple peut être trouvé ici: 004.4’2 SW Dev Swift Package Manager (SPM) avec des ressources Qref

Voir aussi: Utiliser les ressources dans les tests unitaires avec Swift Package Manager

Swift Package Manager (SPM) 4.2

Swift Package Manager PackageDescription 4.2 prend en charge les dépendances locales .

Les dépendances locales sont des packages sur le disque qui peuvent être référé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 portant le même nom dans le graphique du package.

Note: J’attends, mais je n’ai pas encore testé, que quelque chose comme ce qui suit devrait être possible avec 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"] ), ] ) 

Avec swift Swift 3, la syntaxe self.dynamicType est obsolète, utilisez plutôt cette syntaxe self.dynamicType

 let testBundle = Bundle(for: type(of: self)) let fooTxtPath = testBundle.path(forResource: "foo", ofType: "txt") 

ou

 let fooTxtURL = testBundle.url(forResource: "foo", withExtension: "txt") 

Confirmez que la ressource est ajoutée à la cible de test.

entrer la description de l'image ici

Si vous avez plusieurs cibles dans votre projet, vous devez append des ressources entre les différentes cibles disponibles dans l’ appartenance à la cible et vous devrez peut-être basculer entre différentes cibles en 3 étapes, comme illustré ci-dessous.

entrer la description de l'image ici