Une implémentation Swift :
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 principaux et de test pour 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, une test unitaire chemin du paquet 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 séparée de la Developer/CoreSimulator/Devices
chemin normal (non testé par l'unité) du faisceau de données :
/Users/
UserName/
Library/
Developer/
CoreSimulator/
Devices/
_UUID_/
data/
Containers/
Bundle/
Application/
_UUID_/
App.app/
Notez également que l'exécutable du test unitaire est, par défaut, lié au code de l'application. Cependant, le code de test unitaire ne devrait avoir que l'adhésion à Target dans le seul bundle de test. Le code de l'application ne doit avoir une appartenance à la cible que dans le bundle de l'application. Au moment de l'exécution, le bundle cible du test unitaire est injecté dans le paquet 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éera un MyProjectPackageTests.xctest
test bundle. Et, le swift package generate-xcodeproj
créera un MyProjectTests.xctest
test bundle. Ces différents lots de tests ont différents chemins . De plus, les différents paquets de test peuvent avoir certains la structure des répertoires internes et les différences de contenu .
Dans les deux cas, le .bundlePath
y .bundleURL
renverra le chemin du paquet de tests en cours d'exécution sur macOS. Cependant, Bundle
n'est pas actuellement implémenté pour Ubuntu Linux.
De même, la ligne de commande swift build
y swift test
ne fournissent pas actuellement un mécanisme de copie des ressources.
Cependant, avec un peu d'effort, il est possible de mettre en place des processus pour utiliser le Swift Package Manger avec des ressources dans les environnements macOS Xcode, macOS command line et Ubuntu command line. Un exemple peut être trouvé ici : 004.4'2 SW Dev Swift Package Manager (SPM) avec ressources Qref
Voir aussi : Utiliser des ressources dans les tests unitaires avec le gestionnaire de paquets Swift
Gestionnaire de paquets Swift (SwiftPM) 5.3
Swift 5.3 comprend Ressources du gestionnaire de paquets SE-0271 proposition d'évolution avec "Statut : Implémenté (Swift 5.3) ". :-)
Les ressources ne sont pas toujours destinées à être utilisées par les clients du paquet. Une utilisation des ressources peut inclure des tests de montage qui ne sont nécessaires que pour les tests unitaires. De telles ressources ne seraient pas incorporées dans les clients du paquet avec le code de la bibliothèque, mais seraient uniquement utilisées lors de l'exécution des tests du paquet.
- Ajouter un nouveau
resources
dans target
y testTarget
pour permettre de déclarer explicitement les fichiers de ressources.
SwiftPM utilise les conventions du système de fichiers pour déterminer l'ensemble des fichiers sources qui appartiennent à chaque cible d'un paquetage : plus précisément, les fichiers sources d'une cible sont ceux qui sont situés sous le "répertoire cible" désigné pour la cible. Par défaut, il s'agit d'un répertoire portant le même nom que la cible et situé dans "Sources" (pour une cible normale) ou "Tests" (pour une cible de test), mais cet emplacement peut être personnalisé dans le manifeste du paquet.
// Get path to DefaultSettings.plist file.
let path = Bundle.module.path(forResource: "DefaultSettings", ofType: "plist")
// Load an image that can be in an asset archive in a bundle.
let image = UIImage(named: "MyIcon", in: Bundle.module, compatibleWith: UITraitCollection(userInterfaceStyle: .dark))
// Find a vertex function in a compiled Metal shader library.
let shader = try mtlDevice.makeDefaultLibrary(bundle: Bundle.module).makeFunction(name: "vertexShader")
// Load a texture.
let texture = MTKTextureLoader(device: mtlDevice).newTexture(name: "Grass", scaleFactor: 1.0, bundle: Bundle.module, options: options)
Ejemplo
// swift-tools-version:5.3
import PackageDescription
targets: [
.target(
name: "CLIQuickstartLib",
dependencies: [],
resources: [
// Apply platform-specific rules.
// For example, images might be optimized per specific platform rule.
// If path is a directory, the rule is applied recursively.
// By default, a file will be copied if no rule applies.
.process("Resources"),
]),
.testTarget(
name: "CLIQuickstartLibTests",
dependencies: [],
resources: [
// Copy directories as-is.
// Use to retain directory structure.
// Will be at top level in bundle.
.copy("Resources"),
]),
Numéro actuel
Xcode
Bundle.module
est généré par SwiftPM (voir Build/BuildPlan.swift SwiftTargetBuildDescription generateResourceAccessor() ) et ne sont donc pas présents dans Fondation.Bundle quand il est construit par Xcode.
Une approche comparable dans Xcode serait d'ajouter manuellement un fichier Resources
au module, ajoutez une phase de construction Xcode copy
pour mettre le Resource
dans certains *.bundle
et ajoutez un #ifdef Xcode
pour que la compilation de Xcode fonctionne avec les ressources.
#if Xcode
extension Foundation.Bundle {
/// Returns resource bundle as a `Bundle`.
/// Requires Xcode copy phase to locate files into `*.bundle`
/// or `ExecutableNameTests.bundle` for test resources
static var module: Bundle = {
var thisModuleName = "CLIQuickstartLib"
var url = Bundle.main.bundleURL
for bundle in Bundle.allBundles
where bundle.bundlePath.hasSuffix(".xctest") {
url = bundle.bundleURL.deletingLastPathComponent()
thisModuleName = thisModuleName.appending("Tests")
}
url = url.appendingPathComponent("\(thisModuleName).bundle")
guard let bundle = Bundle(url: url) else {
fatalError("Bundle.module could not load: \(url.path)")
}
return bundle
}()
/// Directory containing resource bundle
static var moduleDir: URL = {
var url = Bundle.main.bundleURL
for bundle in Bundle.allBundles
where bundle.bundlePath.hasSuffix(".xctest") {
// remove 'ExecutableNameTests.xctest' path component
url = bundle.bundleURL.deletingLastPathComponent()
}
return url
}()
}
#endif