Jak zaimportować plik Swift z innego pliku Swift?

154

Chcę po prostu dołączyć moją klasę Swift z innego pliku, na przykład jej 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'"    
}

Oba pliki Swift znajdują się w tym samym katalogu.

joseph.hainline
źródło
2
Według Apple Docs nie potrzebujesz importu, gdy oba pliki mają ten sam cel. Niestety testy mają inny cel. Jednym z możliwych rozwiązań może być wykonanie instrukcji importu za pomocą yourModule / PrimeNumberModel.
Alex Reynolds
@ joseph.hainline Mam ten sam problem. Jak to zostanie rozwiązane? Teraz utknąłem.
Deweloper,

Odpowiedzi:

131

Miałem ten sam problem, także w moich XCTestCaseplikach, ale nie w zwykłych plikach projektu.

Aby pozbyć się:

Użycie nierozwiązanego identyfikatora „PrimeNumberModel”

Potrzebowałem do importmodułu podstawowego w pliku testowym. W moim przypadku mój cel nazywa się „mój import myprojectprojekt ” i dodałem i klasa została rozpoznana.

H6.
źródło
2
To wymaga więcej głosów pozytywnych. Odpowiedzi radzące po prostu dodać plik .swift do celu testowego nie są dokładnie błędne, ale nie tak powinno być
poniżej
10
Ale co zrobić z nazwą projektu „Wildlife League”, w której jest miejsce?
allenlinli
59
Począwszy od Beta 4, musisz również upewnić się, że ustawienia kontroli dostępu są prawidłowe. Będziesz musiał wyraźnie ustawić zarówno testowaną klasę, jak i funkcje, które testujesz w tej klasie jako public. W przeciwnym razie XCTestCasepodklasa nie będzie w stanie „zobaczyć” tego, co próbujesz przetestować. Zmarnowałem kilka godzin tej ostatniej nocy :)
Erik P. Hansen
2
Jeśli się nie mylę, nazwa modułu produktu (w ustawieniach kompilacji docelowej) nie zawsze jest taka sama jak nazwa celu i jest to nazwa modułu, która powinna być używana w importinstrukcji
csch
3
Jeśli cel Swift ma w nazwie spację, można ją zaimportować, zastępując spacje podkreśleniami w instrukcji import. „Moja klasa Swift” staje się „My_Swift_Class”.
Cin316
70

AKTUALIZACJA Swift 2.x, 3.x, 4.x i 5.x

Teraz nie musisz dodawać publicdo metod testowania. W nowszych wersjach Swift konieczne jest jedynie dodanie @testablesłowa kluczowego.

PrimeNumberModelTests.swift

import XCTest
@testable import MyProject

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

A twoje wewnętrzne metody mogą się utrzymać Internal

PrimeNumberModel.swift

import Foundation

class PrimeNumberModel {
   init() {
   }
}

Pamiętaj, że symbole private(i fileprivate) nie są dostępne nawet przy użyciu @testable.


Swift 1.x

Istnieją dwie istotne koncepcje ze Swift (As Xcode 6 beta 6).

  1. Nie musisz importować klas Swift, ale musisz zaimportować zewnętrzne moduły (cele)
  2. Domyślny poziom kontroli dostępu w Swift toInternal access

Biorąc pod uwagę, że testy są na innym celu PrimeNumberModelTests.swift, musisz do importcelu zawierającego klasę, którą chcesz przetestować, jeśli twój cel zostanie wywołany, MyProjectbędziesz musiał dodać import MyProjectdo PrimeNumberModelTests:

PrimeNumberModelTests.swift

import XCTest
import MyProject

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

Ale to nie wystarczy, aby przetestować swoją klasę PrimeNumberModel, ponieważ domyślny poziom kontroli dostępu to Internal Access, Twoja klasa nie będzie widoczna dla pakietu testowego, więc musisz to zrobić Public Accessi wszystkie metody, które chcesz przetestować:

PrimeNumberModel.swift

import Foundation

public class PrimeNumberModel {
   public init() {
   }
}
Diogo T.
źródło
czy istnieje sposób na zmianę domyślnej kontroli dostępu? Miałem zabawny przypadek, że kiedyś działał bez publicznego modyfikatora, po prostu przeniosłem przypadki testowe, nagle przestał działać.
Metaphox,
Myślę, że nie jest to możliwe, przynajmniej w obecnej wersji swift.
Diogo T
dzięki. I dowiedziałem się, że moim problemem było to, że plik Swift nie jest kompilowany do celu testowego z przypadkami testowymi.
Metaphox,
1
tak, to było dokładnie miejsce, w którym czułem się źle - nie powinienem budować pliku szybkiego klasy w celu przypadku testowego. fajny post na blogu! dzięki.
Metaphox,
1
Jeśli masz projekt utworzony w Xcode 5 lub nowszym i wybierasz podejście „publiczny dostęp, importuj moduł docelowy”, sprawdź dwukrotnie nazwę modułu dla celu testowego, ponieważ może być taka sama jak główny cel. Jeśli otrzymujesz No such module <moduleName>błąd kompilacji w swoim przypadku testowym, możesz chcieć sprawdzić PRODUCT_MODULE_NAMEcel testowy. Świetna odpowiedź Diogo.
Chris
48

W Dokumentacji jest napisane, że w Swift nie ma instrukcji importu.

wprowadź opis obrazu tutaj

Po prostu użyj:

let primNumber = PrimeNumberModel()
Nitin Gohel
źródło
2
To zadziałało, ale musiałem zamknąć i ponownie otworzyć Xcode 6.0, aby klasa wreszcie się pojawiła. Spróbuj również wyczyścić i zbudować projekt.
user3344977
Wydaje się, że jest to nowość (lub problem) w najnowszych wersjach beta XCode 6.3, więc instrukcja importu jest teraz konieczna. W języku Swift znajduje się również instrukcja importu do importowania modułów.
Augunrik
Zgodnie z dostarczoną dokumentacją ta tabela z instrukcją „Brak instrukcji importu” dotyczy przypadku „Import z tego samego celu”. W przypadku XCTests używasz innego celu (testowego), więc zwróć uwagę na sekcję „Importowanie zewnętrznych struktur” w artykule, jest kolejna tabela: Dowolny framework językowy -> Importuj do Swift -> importuj „FrameworkName” jest potrzebny
Igor Vasilev
Jeśli zauważysz problem w edytorze, często jest to cel testowy, który nie zawiera klasy. Więc prawdopodobnie dobrze zbudujesz swój runnable, ale jeśli którykolwiek z celów ma problem, nadal wyświetla błąd. Gdybyś wybrał jeden z tych innych celów, nie pozwoliłby ci na kompilację.
Joel Teply
34

Sprawdź członkostwo docelowe PrimeNumberModel.swift w swoim celu testowym.

kimkkikki
źródło
1
proszę dodać to jako komentarz.
4dgaurav
8
Ta osoba nie może, potrzebuje 9 więcej przedstawicieli, aby to zrobić (w momencie pisania).
AlbertEngelB
1
Jaki do cholery jest cel?
Użytkownik
Dzięki, to zadziałało dla mnie. Kliknij plik zajęć. Sprawdź pierwszą zakładkę kolumny inspektora po prawej stronie. Druga sekcja to „Członkostwo docelowe”. Upewnij się, że cel / produkt, który próbujesz uwzględnić w klasie, jest zaznaczony.
Hairgami_Master
1
Nie jest to ściśle odpowiedź na pytanie „jak zaimportować ...”, ale odpowiedziała na pytanie, które mnie tu sprowadziło (zapomniałem dodać nowy plik do celu). Tak więc dla mnie i innych osób, które przyjdą tutaj, podążając za pierwszym wynikiem Google dotyczącym „szybkiej nierozwiązanej klasy identyfikatora”, jest to odpowiedź (a nie komentarz).
noamtm
17

W Objective-C, jeśli chcesz użyć klasy w innym pliku, musisz ją zaimportować:

#import "SomeClass.h"

Jednak w Swift nie musisz w ogóle importować. Po prostu użyj go tak, jakby był już zaimportowany.

Przykład

// This is a file named SomeClass.swift

class SomeClass : NSObject {

}

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

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

Jak widać, import nie był potrzebny. Mam nadzieję że to pomoże.

Fomentia
źródło
Dzięki! Wciąż poruszam się po tych wszystkich nowych rzeczach w Swift.
Felipe
5

Według Apple nie potrzebujesz importu plików Swift w tym samym celu. W końcu udało mi się to uruchomić, dodając mój szybki plik zarówno do mojego zwykłego celu, jak i celu testowego. Następnie użyłem nagłówka mostkującego do testu, aby upewnić się, że moje pliki ObjC, do których odwoływałem się w moim zwykłym nagłówku mostkowania, są dostępne. Biegał teraz jak urok.

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.
    }
}

}

Dlatego upewnij się, że PrimeNumberModel ma cel Twojego celu testowego. Lub rozwiązanie High6 polegające na imporcie całego modułu będzie działać

Alex Reynolds
źródło
Czy to działa tylko w przypadku klas logiki / modelu, czy mogę go również używać dla delegata aplikacji?
Nicolas Miari,
5

Udało mi się rozwiązać ten problem, czyszcząc moją kompilację.

Górne menu -> Produkt -> Wyczyść lub skrót klawiaturowy: Shift+ Cmd+K

Peter Fisher
źródło
4

Od wersji Swift 2.0 najlepszą praktyką jest:

Dodaj wiersz @testable import MyAppna początku pliku testów, gdzie „MojaApl.” To nazwa modułu produktu celu aplikacji (widoczna w ustawieniach kompilacji celu aplikacji ). Otóż ​​to.

(Zwróć uwagę, że nazwa modułu produktu będzie taka sama, jak nazwa celu aplikacji, chyba że nazwa celu aplikacji zawiera spacje, które zostaną zastąpione podkreśleniami. Na przykład, jeśli mój cel aplikacji nazywa się „Zabawna gra”, napiszę @testable import Fun_Gamew najlepsze z moich testów.)

George WS
źródło
1

Musisz dodać procedurę, do której kompilator będzie odwoływał się jako punkt wejścia, więc dodaj plik main.swift, który w tym przypadku po prostu tworzy instancję twojego pliku testowego:

main.swift

PrimeNumberModelTests()

Następnie skompiluj w wierszu poleceń (używam El Capitan i Swift 2.2):

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

W takim przypadku pojawi się ostrzeżenie: wynik inicjatora jest nieużywany , ale program kompiluje się i jest wykonywalny:

./PrimeNumberMain

UWAGA: dla uproszczenia usunąłem import typu XCTest i XCTestCase.

Szyszka
źródło
1

Sprawdź ustawienia PrimeNumberModelTestscelu.

Jeśli nie widzisz PrimeNumberModel.swiftpliku w Build Phases/Compile Sources, dodaj go.

Bumseok
źródło
To nie jest właściwy sposób, sprawdź odpowiedź High6.
Diogo T
0

Więc musisz

  1. Importuj zewnętrzne moduły, których chcesz użyć
  2. Upewnij się, że masz odpowiednie modyfikatory dostępu do klasy i metod, których chcesz użyć.

W moim przypadku miałem plik Swift, który chciałem przetestować jednostkowo, a plik testu jednostkowego był również klasą Swift. Upewniłem się, że modyfikatory dostępu są poprawne, ale oświadczenie

import stMobile

(powiedzmy, że stMobile to nasza nazwa docelowa)

nadal nie działał (ciągle otrzymywałem błąd „Nie ma takiego modułu”), sprawdziłem cel i faktycznie jego nazwa brzmiała stMobile. Więc poszedłem do ustawień kompilacji, pod opakowaniem i znalazłem nazwę modułu produktu iz jakiegoś powodu nazywało się to St_Mobile, więc zmieniłem moje oświadczenie importu

import St_Mobile

(która jest nazwą modułu produktu ) i wszystko działało.

Więc by podsumować:

  1. Sprawdź nazwę modułu produktu i użyj poniższej instrukcji importu w klasie testów jednostkowych

    import myProductModuleName
  2. Upewnij się, że modyfikatory dostępu są poprawne (poziom klasy i metody).

Cloud9999Strife
źródło
0

Zamiast wymagać jawnego importu, kompilator Swift niejawnie wyszukuje .swiftmodulepliki bibliotek Swift zależności.

Xcode może zbudować dla Ciebie szybkie moduły lub zapoznać się z blogiem dotyczącym oprogramowania railsware, aby uzyskać instrukcje wiersza poleceń dotyczące swiftc.

mcandre
źródło
0

Jak @ high6 i @ erik-p-hansen wskazali w odpowiedzi udzielonej przez @ high6, można temu zaradzić, importując cel modułu, w którym znajduje się klasa PrimeNumberModel, która prawdopodobnie ma taką samą nazwę jak Twój projekt w prostym projekcie .

Patrząc na to, natknąłem się na artykuł Napisz swój pierwszy test jednostkowy w języku Swift na swiftcast.tv autorstwa Claytona McIlratha. Omawia modyfikatory dostępu, pokazuje przykład tego samego problemu, który masz (ale dla ViewController zamiast pliku modelu) i pokazuje, jak zarówno zaimportować cel, jak i rozwiązać problem modyfikatora dostępu, włączając plik docelowy do celu, co oznacza nie musisz upubliczniać klasy, którą próbujesz przetestować, chyba że rzeczywiście tego chcesz.

mr_sd
źródło