Comment importer un fichier Swift à partir d'un autre fichier Swift?

154

Je veux simplement inclure ma classe Swift à partir d'un autre fichier, comme son test

PrimeNumberModel.swift

import Foundation

class PrimeNumberModel { }

PrimeNumberModelTests.swift

import XCTest
import PrimeNumberModel  // gives me "No such module 'PrimeNumberModel'"

class PrimeNumberModelTests: XCTestCase {
    let testObject = PrimeNumberModel()  // "Use of unresolved identifier 'PrimeNumberModel'"    
}

Les deux fichiers Swift se trouvent dans le même répertoire.

joseph.hainline
la source
2
Selon les documents Apple, vous n'avez pas besoin d'une importation lorsque les deux fichiers ont la même cible. Malheureusement, les tests ont un objectif différent. Une solution possible pourrait être de faire une instruction d'importation à l'aide de yourModule / PrimeNumberModel.
Alex Reynolds le
@ joseph.hainline Je suis confronté au même problème. Comment cela sera-t-il résolu? Je suis coincé maintenant.
Développeur

Réponses:

131

J'ai eu le même problème, également dans mes XCTestCasefichiers, mais pas dans les fichiers de projet réguliers.

Pour se débarrasser de:

Utilisation de l'identifiant non résolu 'PrimeNumberModel'

J'avais besoin importdu module de base dans le fichier de test. Dans mon cas, ma cible s'appelle « mon projet » et j'ai ajouté import myprojectet la classe a été reconnue.

H6.
la source
2
Cela nécessite plus de votes positifs. Les réponses conseillant d'ajouter simplement le fichier .swift à la cible de test ne sont pas tout à fait fausses, mais ce n'est pas la manière dont cela devrait être fait
dessous du
10
Mais que faire de mon nom de projet "Wildlife League", qui contient de l'espace?
allenlinli
59
À partir de la version bêta 4, vous devrez également vous assurer que vos paramètres de contrôle d'accès sont corrects. Vous devrez définir explicitement à la fois la classe que vous testez et les fonctions que vous testez dans cette classe public. Sinon, la XCTestCasesous - classe ne pourra pas "voir" ce que vous essayez de tester. J'ai perdu quelques heures sur cette dernière nuit :)
Erik P. Hansen
2
Si je ne me trompe pas, le nom du module de produit (dans les paramètres de construction de la cible) n'est pas toujours le même que le nom de la cible et c'est le nom du module qui doit être utilisé dans la importdéclaration
csch
3
Si une cible Swift a un espace dans son nom, vous pouvez l'importer en remplaçant les espaces par des traits de soulignement dans l'instruction d'importation. «Ma classe Swift» devient «My_Swift_Class».
Cin316
70

MISE À JOUR Swift 2.x, 3.x, 4.x et 5.x

Vous n'avez plus besoin d'ajouter publicles méthodes à tester. Sur les versions plus récentes de Swift, il suffit d'ajouter le @testablemot - clé.

PrimeNumberModelTests.swift

import XCTest
@testable import MyProject

class PrimeNumberModelTests: XCTestCase {
    let testObject = PrimeNumberModel()
}

Et vos méthodes internes peuvent garder Internal

PrimeNumberModel.swift

import Foundation

class PrimeNumberModel {
   init() {
   }
}

Notez que les symboles private(et fileprivate) ne sont pas disponibles même avec l'utilisation @testable.


Swift 1.x

Il y a deux concepts pertinents de Swift ici (comme Xcode 6 beta 6).

  1. Vous n'avez pas besoin d'importer des classes Swift, mais vous devez importer des modules externes (cibles)
  2. Le niveau de contrôle d'accès par défaut dans Swift estInternal access

Étant donné que les tests sont sur une autre cible, PrimeNumberModelTests.swiftvous avez besoin de importla cible qui contient la classe que vous souhaitez tester, si votre cible est appelée MyProject, vous devrez ajouter import MyProjectau PrimeNumberModelTests:

PrimeNumberModelTests.swift

import XCTest
import MyProject

class PrimeNumberModelTests: XCTestCase {
    let testObject = PrimeNumberModel()
}

Mais cela ne suffit pas pour tester votre classe PrimeNumberModel, puisque le niveau de contrôle d'accès par défaut est Internal Access, votre classe ne sera pas visible pour le bundle de test, vous devez donc le créer Public Accesset toutes les méthodes que vous souhaitez tester:

PrimeNumberModel.swift

import Foundation

public class PrimeNumberModel {
   public init() {
   }
}
Diogo T
la source
existe-t-il un moyen de modifier le contrôle d'accès par défaut? J'ai eu un cas drôle qui fonctionnait sans modificateur public très bien, puis j'ai déplacé les cas de test, il a soudainement cessé de fonctionner.
Metaphox
Je pense que ce n'est pas possible, du moins pour la version actuelle de swift.
Diogo T
Merci. Et j'ai découvert que mon problème était que le fichier swift n'était pas construit sur la cible de test avec les cas de test.
Metaphox
1
oui, c'était exactement là que je me sentais mal - je ne devrais pas créer le fichier swift de classe dans la cible du scénario de test. bel article de blog! Merci.
Metaphox le
1
Si vous avez un projet créé avec Xcode 5 ou version ultérieure et que vous optez pour l'approche «accès public, importation du module cible», vérifiez le nom du module de votre cible de test car il peut être le même que la cible principale. Si vous recevez une No such module <moduleName>erreur de compilation dans votre scénario de test, vous pouvez vérifier la PRODUCT_MODULE_NAMEpour la cible de test. Grande réponse Diogo.
Chris
48

Dans la documentation, il est indiqué qu'il n'y a pas d'instructions d'importation dans Swift.

entrez la description de l'image ici

Utilisez simplement:

let primNumber = PrimeNumberModel()
Nitin Gohel
la source
2
Cela a fonctionné mais j'ai dû fermer et rouvrir Xcode 6.0 pour que la classe apparaisse enfin. Essayez également de nettoyer et de construire le projet.
user3344977
Cela semble être nouveau (ou un problème) dans la dernière version bêta de XCode 6.3, donc la déclaration d'importation est maintenant nécessaire. Il existe également une instruction d'importation dans Swift, pour importer des modules.
Augunrik
Selon la documentation fournie, ce tableau avec "Aucune déclaration d'importation" est lié au cas "Importer depuis la même cible". Dans le cas de XCTests, vous utilisez une cible (de test) différente, alors observez la section "Importation de cadres externes" de l'article, il existe un autre tableau: Tout cadre de langage -> Importer dans Swift -> importer "FrameworkName" est nécessaire
Igor Vasilev
Si vous voyez un problème dans l'éditeur, c'est souvent qu'il y a une cible de test qui n'a pas la classe incluse. Donc, vous construisez probablement votre amende exécutable, mais si l'une des cibles rencontre un problème, elle affiche toujours l'erreur. Si vous aviez sélectionné l'une de ces autres cibles, cela ne vous permettrait pas de compiler.
Joel Teply
34

Vérifiez l'appartenance à la cible de PrimeNumberModel.swift dans votre cible de test.

Kimkkikki
la source
1
veuillez l'ajouter en commentaire.
4dgaurav
8
Cette personne ne peut pas, il a besoin de 9 représentants supplémentaires pour le faire (au moment de la rédaction de cet article).
AlbertEngelB
1
Qu'est-ce qu'une cible?
Utilisateur
Merci, cela a fonctionné pour moi. Cliquez sur le fichier de classe. Vérifiez le premier onglet de la colonne de l'inspecteur sur la droite. La deuxième section est "Adhésion cible". Assurez-vous que la cible / le produit que vous essayez d'inclure dans la classe est sélectionné.
Hairgami_Master
1
Ce n'est pas strictement une réponse à la question "comment importer ...", mais cela a répondu à la question que j'avais qui m'a amené ici (j'ai oublié d'ajouter un nouveau fichier à la cible). Donc pour moi, et d'autres qui arriveront ici en suivant le premier résultat google pour "classe d'identifiant rapide non résolue", c'est une réponse (et non un commentaire).
noamtm
17

En Objective-C, si vous vouliez utiliser une classe dans un autre fichier, vous deviez l'importer:

#import "SomeClass.h"

Cependant, dans Swift, vous n'avez pas du tout besoin d'importer. Utilisez-le simplement comme s'il était déjà importé.

Exemple

// This is a file named SomeClass.swift

class SomeClass : NSObject {

}

// This is a different file, named OtherClass.swift

class OtherClass : NSObject {
    let object = SomeClass()
}

Comme vous pouvez le voir, aucune importation n'était nécessaire. J'espère que cela t'aides.

Fomentia
la source
Merci! Je me déplace toujours avec toutes ces nouveautés de Swift.
Felipe
5

Selon Apple, vous n'avez pas besoin d'une importation pour les fichiers rapides dans la même cible. Je l'ai finalement fait fonctionner en ajoutant mon fichier swift à ma cible habituelle et à ma cible de test. Ensuite, j'ai utilisé l'en-tête de pontage pour le test pour m'assurer que mes fichiers ObjC que j'ai référencés dans mon en-tête de pontage régulier étaient disponibles. Ran comme un charme maintenant.

import XCTest
//Optionally you can import the whole Objc Module by doing #import ModuleName

class HHASettings_Tests: XCTestCase {

override func setUp() {
    let x : SettingsTableViewController = SettingsTableViewController()

    super.setUp()
    // Put setup code here. This method is called before the invocation of each test method in the class.
}

override func tearDown() {
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    super.tearDown()
}

func testExample() {
    // This is an example of a functional test case.
    XCTAssert(true, "Pass")
}

func testPerformanceExample() {
    // This is an example of a performance test case.
    self.measureBlock() {
        // Put the code you want to measure the time of here.
    }
}

}

Assurez-vous donc que PrimeNumberModel a une cible de votre cible de test. Ou la solution High6 d'importation de votre module entier fonctionnera

Alex Reynolds
la source
Cela fonctionne-t-il uniquement pour les classes de logique / modèle, ou puis-je également l'utiliser pour le délégué d'application?
Nicolas Miari
5

J'ai pu résoudre ce problème en nettoyant ma version.

Menu supérieur -> Produit -> Raccourci clavier Nettoyer ou: Shift+ Cmd+K

Peter Fisher
la source
4

Depuis Swift 2.0, les meilleures pratiques sont:

Ajoutez la ligne @testable import MyAppen haut de votre fichier de tests, où "MyApp" est le nom du module de produit de votre cible d'application (visible dans les paramètres de construction de votre cible d'application ). C'est tout.

(Notez que le nom du module de produit sera le même que le nom de votre cible d'application, sauf si le nom de votre cible d'application contient des espaces, qui seront remplacés par des traits de soulignement. Par exemple, si ma cible d'application s'appelait "Fun Game", j'écrirais @testable import Fun_Gameà la haut de mes tests.)

George WS
la source
1

Vous devez ajouter une routine pour que le compilateur fasse référence en tant que point d'entrée, alors ajoutez un fichier main.swift, qui dans ce cas crée simplement une instance de votre fichier de test:

main.swift

PrimeNumberModelTests()

Ensuite, compilez sur la ligne de commande (j'utilise El Capitan et Swift 2.2):

xcrun -sdk macosx swiftc -emit-executable -o PrimeNumberMain PrimeNumberModel.swift PrimeNumberModelTests.swift main.swift

Dans ce cas, vous obtiendrez un avertissement: le résultat de l'initialiseur n'est pas utilisé , mais le programme se compile et est exécutable:

./PrimeNumberMain

CAVEAT: J'ai supprimé le type d'importation XCTest et XCTestCase pour plus de simplicité.

Pomme de pin
la source
1

Vérifiez vos PrimeNumberModelTestsparamètres de cible.

Si vous ne voyez pas le PrimeNumberModel.swiftfichier dans Build Phases/Compile Sources, ajoutez-le.

Bumseok
la source
Ce n'est pas la bonne façon de le faire, vérifiez la réponse High6.
Diogo T
0

Donc, vous devez

  1. Importez les modules externes que vous souhaitez utiliser
  2. Et assurez-vous d'avoir les bons modificateurs d'accès sur la classe et les méthodes que vous souhaitez utiliser.

Dans mon cas, j'avais un fichier rapide que je voulais tester unitaire, et le fichier de test unitaire était également une classe rapide. Je me suis assuré que les modificateurs d'accès étaient corrects, mais la déclaration

import stMobile

(disons que stMobile est notre nom cible)

ne fonctionnait toujours pas (j'obtenais toujours l'erreur «No such module»), j'ai vérifié ma cible, et son nom était en effet stMobile. Donc, je suis allé dans les paramètres de construction, sous l'emballage, et j'ai trouvé le nom du module de produit, et pour une raison quelconque, cela s'appelait St_Mobile, j'ai donc changé ma déclaration d'importation

import St_Mobile

(qui est le nom du module de produit ), et tout a fonctionné.

Pour résumer:

  1. Vérifiez le nom de votre module de produit et utilisez l'instruction d'importation ci-dessous dans votre classe de test unitaire

    import myProductModuleName
  2. Assurez-vous que vos modificateurs d'accès sont corrects (niveau de classe et vos méthodes).

Cloud9999Strife
la source
0

Au lieu d'exiger des importations explicites, le compilateur Swift recherche implicitement les .swiftmodulefichiers des bibliothèques Swift de dépendance.

Xcode peut créer des modules Swift pour vous, ou consultez le blog railsware pour obtenir des instructions en ligne de commande pour swiftc.

mcandre
la source
0

Comme @ high6 et @ erik-p-hansen l'ont souligné dans la réponse donnée par @ high6, cela peut être surmonté en important la cible du module où se trouve la classe PrimeNumberModel, qui est probablement le même nom que votre projet dans un projet simple .

En regardant cela, je suis tombé sur l'article Écrivez votre premier test unitaire en Swift sur swiftcast.tv par Clayton McIlrath. Il traite des modificateurs d'accès, montre un exemple du même problème que vous rencontrez (mais pour un ViewController plutôt qu'un fichier de modèle) et montre comment à la fois importer la cible et résoudre le problème du modificateur d'accès en incluant le fichier de destination dans la cible, ce qui signifie vous n'êtes pas obligé de rendre publique la classe que vous essayez de tester, sauf si vous le souhaitez réellement.

mr_sd
la source