NSURL de chemin d'accès au fichier dans l'essai bundle avec XCTest

j'essaie d'écrire une application iOS en utilisant TDD et le nouveau cadre XCTest. Une de mes méthodes consiste à extraire un fichier de l'internet (à partir d'un objet NSURL) et à le stocker dans les documents de l'utilisateur. La signature de la méthode est similaire à:

- (void) fetchAndStoreImage:(NSURL *)imageUrl

j'essaie d'écrire le test de cette méthode d'une manière qui n'échoue pas s'il n'y a pas de connexion à internet. Mon approche (prise d'un précédent question ) est d'appeler la méthode utilisation D'un NSURL pour une image dans le système de fichiers local.

Lorsqu'un nouveau projet avec des tests unitaires activés est créé, le répertoire Tests a un sous-répertoire nommé 'Supporting Files'. Je suppose que c'est là que mes images de test devraient aller. Ma question Est Comment puis-je obtenir un objet NSURL qui pointe vers une image dans ce répertoire, car je ne voudrais pas que les images de test soient empaquetées avec l'application. Toute aide est appréciée.

66
demandé sur Community 2013-10-11 06:03:22

6 réponses

En fait, le [NSBundle mainBundle] lors de l'exécution d'un UnitTest est pas le chemin de votre application, mais est /Développeur/usr/bin, donc cela ne fonctionnera pas.

La façon d'obtenir des ressources dans une unité de test est ici: OCUnit & NSBundle

en bref, utiliser:

[[NSBundle bundleForClass:[self class]] resourcePath]

ou dans votre cas:

[[NSBundle bundleForClass:[self class]] resourceURL]
116
répondu Ben Clayton 2018-06-15 20:43:17

Swift 2:

let testBundle = NSBundle(forClass: self.dynamicType)
let fileURL = testBundle.URLForResource("imageName", withExtension: "png")
XCTAssertNotNil(fileURL)

Swift 3, 4:

let testBundle = Bundle(for: type(of: self))
let fileURL = testBundle.url(forResource: "imageName", withExtension: "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

L'URL Xcode 6/7/8 sera dans Developer/Xcode/DerivedData quelque chose comme ...

file:///Users/
  UserName/
    Library/
      Developer/
        Xcode/
          DerivedData/
            App-qwertyuiop.../
              Build/
                Products/
                  Debug-iphonesimulator/
                    AppTests.xctest/
                      imageName.png

... qui est séparé de L'URL Developer/CoreSimulator/Devices

file:///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. Cependant, le code de test unitaire ne devrait avoir L'appartenance de cible que dans le faisceau de test. Le code de demande ne devrait viser que L'adhésion au groupe de demandes. À l'exécution, le faisceau de cible d'essai unitaire est injecté dans le faisceau d'application pour exécution .

Swift Package Manager (SPM) 4:

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

Note: par défaut, la ligne de commande swift test créera un faisceau de tests MyProjectPackageTests.xctest . Et, le swift package generate-xcodeproj va créer un faisceau d'essai MyProjectTests.xctest . Ces différents faisceaux d'essai ont différentes voies . en outre, les différents faisceaux d'essai peuvent avoir quelque la structure de répertoire interne et les différences de contenu .

dans les deux cas, le .bundlePath et le .bundleURL retourneront la trajectoire du faisceau d'essai actuellement exécuté sur macOS. Cependant, Bundle n'est pas actuellement mis en œuvre pour Ubuntu.

de plus, les lignes de commande swift build et swift test ne fournissent pas de mécanisme pour copier des ressources.

cependant, avec un certain effort, il est possible de mettre en place des processus pour utiliser le Gestionnaire de paquets Swift 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) With Resources Qref

"1519190920 Swift" Gestionnaire de paquets (SPM) 4.2

Swift Package Manager "1519650920 PackageDescription 4.2 introduit le support de dépendances locales .

les dépendances locales sont des paquets sur disque qui peuvent être référés directement en utilisant leurs chemins. Les dépendances locales ne sont autorisées que dans le paquet racine et elles supplantent toutes les dépendances portant le même nom dans le graphique du paquet.

Note: je m'attends, mais je n'ai pas encore testé, à ce que quelque chose comme ceci soit possible avec le 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"]
        ),
    ]
)
36
répondu l --marc l 2018-07-01 00:32:31

juste pour ajouter pour corriger la réponse, ceci est un exemple comment obtenir filePath pour un fichier dans vos UnitTests / fichiers de soutien:

NSString *filePath = [[[NSBundle bundleForClass:[self class]] resourcePath] stringByAppendingPathComponent:@"YourFileName.json"];
XCTAssertNotNil(filePath);

ce sera probablement utile pour quelqu'un.

13
répondu wzbozon 2014-11-13 18:49:10
  1. vous pouvez référencer des fichiers pack comme dans n'importe quelle cible.
  2. vérifiez si le fichier est copié dans la phase de compilation des ressources du paquet de copies (de votre cible de test)
  3. pour accéder au fichier local:

    NSURL*imageUrl=[[NSBundle mainBundle]URLForResource:@"imageName" withExtension:@"png"];
    

vous pouvez faire un accès asynchrone et attendre la réponse en utilisant: https://github.com/travisjeffery/TRVSMonitor

si vous avez ajouté: dataset1.json dans la cible de test (2):

NSString *p=[[NSBundle mainBundle] pathForResource:@"dataset1" ofType:@"json"];
NSLog(@"%@",p);

2013-10-29 15:49:30.547 PlayerSample[13771: 70b] WT(0): /Users/bpds/Library/Application Support/iPhone Simulator/7.0/Applications/7F78780B-684A-40E0-AA35-A3B5D8AA9DBD/PlayerSample.App.app / dataset1.json

3
répondu bpds 2018-06-15 20:49:12

le problème auquel je faisais face était que le code d'application essayait d'accéder au groupe principal pour des choses comme bundleIdentifier et puisque le groupe principal n'était pas mon projet de test d'unité, il retournerait zéro.

un hack autour de cela qui fonctionne à la fois dans Swift 3.0.1 et Objective-C est de créer une catégorie Objective-C sur NSBundle et de l'inclure dans votre projet de test de l'unité. Tu n'as pas besoin d'une tête de pont ou quoi que ce soit. Cette catégorie va être chargée et maintenant quand vous le code d'application demande le forfait principal votre catégorie vous retournera le forfait d'essai unitaire.

@interface NSBundle (MainBundle)

+(NSBundle *)mainBundle;

@end

@implementation NSBundle (Main)

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+(NSBundle *)mainBundle
{
    return [NSBundle bundleForClass:[SomeUnitTest class]];
}
#pragma clang diagnostic pop

@end
1
répondu odyth 2016-12-18 22:46:37

Voici la version Swift de ceci, Xcode 7, iOS 9, etc.

let testBundle = NSBundle(forClass: self.dynamicType)
let path = testBundle.pathForResource("someImage", ofType: "jpg")
XCTAssertNotNil(path)

Note: someImage.jpg doivent être inclus dans votre cible de test.

0
répondu Dan Rosenstark 2015-12-30 00:14:43