Як імпортувати файл Swift з іншого файлу Swift?


154

Я просто хочу включити свій клас Swift з іншого файлу, як-от його тест

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'"    
}

Обидва швидкі файли знаходяться в одному каталозі.



2
Згідно з документами Apple, вам не потрібно імпортувати, коли обидва файли мають однакову ціль. На жаль, тести мають іншу ціль. Одним з можливих рішень може бути створення заяви про імпорт, використовуючи yourModule / PrimeNumberModel.
Алекс Рейнольдс

@ joseph.hainline Я зіткнувся з тим же питанням. Як це буде вирішено? Я зараз застряг.
Розробник

Відповіді:


131

У мене була така ж проблема, також у моїх XCTestCaseфайлах, але не у звичайних файлах проекту.

Щоб позбутися від:

Використання невирішеного ідентифікатора "PrimeNumberModel"

Мені потрібен importбазовий модуль у тестовому файлі. У моєму випадку моя мета називається «мій проект», і я додав, import myprojectі клас був розпізнаний.


2
Для цього потрібно більше коштів. Відповіді, що рекомендують просто додати файл .swift до тестової цілі, не зовсім помилкові, але це не так, як слід робити
нижче

10
Але що робити з назвою мого проекту "Ліга дикої природи", в якому є місце?
allenlinli

59
Починаючи з бета-версії 4, вам також потрібно буде переконатися в правильності налаштувань контролю доступу. Вам потрібно буде встановити чіткість як класу, який ви тестуєте, так і функцій, які ви тестуєте в цьому класі public. Інакше XCTestCaseпідклас не зможе "побачити" те, що ви намагаєтеся перевірити. Я витратив на цю останню ніч кілька годин :)
Ерік П. Хансен

2
Якщо я не помиляюся, назва продуктового модуля (у налаштуваннях цільової збірки) не завжди відповідає імені цілі, і саме ім'я модуля має використовуватися у importвиписці
csch

3
Якщо ціль Swift має пробіл у своєму імені, ви можете імпортувати її, замінивши пробіли підкресленнями в операторі імпорту. "My Swift Class" стає "My_Swift_Class".
Cin316

70

ОНОВЛЕННЯ Swift 2.x, 3.x, 4.x і 5.x

Тепер вам не потрібно додавати publicметоди до тестування. У новіших версіях Swift потрібно лише додати @testableключове слово.

PrimeNumberModelTests.swift

import XCTest
@testable import MyProject

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

І ваші внутрішні методи можуть зберегти Internal

PrimeNumberModel.swift

import Foundation

class PrimeNumberModel {
   init() {
   }
}

Зауважте, що символи private(та fileprivate) недоступні навіть при використанні @testable.


Швидкий 1.x

Тут є дві відповідні концепції Swift (As Xcode 6 beta 6).

  1. Вам не потрібно імпортувати класи Swift, але вам потрібно імпортувати зовнішні модулі (цілі)
  2. Рівень контролю доступу за замовчуванням у Swift становитьInternal access

Зважаючи на те, що тести перебувають на іншій цілі, PrimeNumberModelTests.swiftвам потрібно досягти importцілі, яка містить клас, який ви хочете перевірити, якщо ваша ціль викликається MyProject, потрібно буде додати import MyProjectдо PrimeNumberModelTests:

PrimeNumberModelTests.swift

import XCTest
import MyProject

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

Але цього недостатньо для тестування вашого класу PrimeNumberModel, оскільки рівень контролю доступу за замовчуванням є Internal Access, ваш клас не буде видно тестовим пакетом, тому вам потрібно зробити його Public Accessта всі методи, які ви хочете перевірити:

PrimeNumberModel.swift

import Foundation

public class PrimeNumberModel {
   public init() {
   }
}

чи можна змінити типовий контроль доступу? У мене був кумедний випадок, що він працював без публічного модифікатора просто чудово, потім я перемістив тестові справи, він раптом перестав більше працювати.
Метафокс

Я думаю, що це неможливо, принаймні для поточної версії швидкої.
Diogo T

Дякую. І я дізнався, що моя проблема полягала в тому, що файл swift не будується до тестової цілі з тестовими кейсами.
Метафокс

1
так, саме там я почував себе неправильно - я не повинен створювати файл класу швидких файлів у ціль тестового випадку. приємна публікація в блозі! Дякую.
Metaphox

1
Якщо у вас є проект, створений за допомогою Xcode 5 або пізнішої версії, і ви вибираєте підхід "загальнодоступний доступ, імпорт цільового модуля", двічі перевірте ім'я модуля для вашої тестової цілі, оскільки воно може бути таким самим, як основне. Якщо No such module <moduleName>у вашому тестовому випадку ви отримуєте помилку компіляції, ви можете перевірити наявність PRODUCT_MODULE_NAMEцілі тесту. Чудова відповідь Діого.
Кріс,

48

У Документації сказано, що у Swift відсутні заяви про імпорт.

введіть тут опис зображення

Просто використовуйте:

let primNumber = PrimeNumberModel()

2
Це спрацювало, але мені довелося закрити і знову відкрити Xcode 6.0, щоб клас нарешті з'явився. Спробуйте також очистити та створити проект.
користувач3344977

Це здається новим (або проблемою) в останній бета-версії XCode 6.3, тому заява про імпорт зараз необхідна. Також у Swift є заява про імпорт, щоб імпортувати модулі.
Аугунрік

Відповідно до наданої документації, ця таблиця з "Немає заяви про імпорт" пов'язана із випадком "Імпорт з тієї ж цільової". У разі XCTests ви використовуєте різні (тест) мети, тому спостерігати в розділі «Імпорт зовнішніх Платформи» статті, є ще одна таблиця: Будь-які рамки мови -> Імпорт в Swift -> імпорт «FrameworkName» потрібен
Ігор Васильєв

Якщо ви бачите проблему в редакторі, часто є тестова ціль, яка не включає клас. Таким чином, ви, ймовірно, будуєте свій штраф, який можна виконати, але якщо з будь-якою з цілей виникає проблема, вона все одно показує помилку. Якщо ви вибрали одну з цих інших цілей, вона не дозволить вам скласти.
Джоель Теплі

34

Перевірте цільову приналежність PrimeNumberModel.swift у своїй тестовій цілі.


1
будь ласка, додайте це як коментар.
4dgaurav

8
Ця людина не може, для цього йому потрібно ще 9 представників (під час написання).
AlbertEngelB

1
Яка біса ціль?
Користувач

Дякую, це працювало на мене. Клацніть на файлі класу. Перевірте першу вкладку стовпчика інспектора праворуч. Другий розділ - «Цільове членство». Переконайтесь, що вибрано ціль / продукт, до якого ви намагаєтеся включити клас.
Hairgami_Master

1
Це не суворо відповідь на питання "як я імпортую ...", але він відповів на питання, яке я привів мене сюди (я забув додати новий файл до цілі). Так що для мене, і інших , які будуть приїжджати сюди після першого результату Google для «швидкого класу недозволеного ідентифікатора», це є відповідь (а не коментар).
noamtm

17

У Objective-C, якщо ви хочете використовувати клас в іншому файлі, вам довелося імпортувати його:

#import "SomeClass.h"

Однак у Swift взагалі не потрібно імпортувати. Просто використовуйте її так, ніби вона вже була імпортною.

Приклад

// This is a file named SomeClass.swift

class SomeClass : NSObject {

}

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

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

Як бачите, імпорт не потрібен. Сподіваюся, це допомагає.


Дякую! Все ще обіймаю всі ці нові речі від Swift.
Феліпе

5

На думку Apple, вам не потрібно імпортувати швидкі файли в тій самій цілі. Нарешті, я працював, додавши свій швидкий файл до моєї звичайної цілі та тестової цілі. Тоді я використовував мостовий заголовок для тесту, щоб переконатися, що мої файли ObjC, на які я посилався у своєму звичайному мостовому заголовку, були доступні. Побіг, як чарівність, зараз.

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

}

Тому переконайтеся, що PrimeNumberModel має ціль тестової цілі. Або рішення High6 про імпорт цілого модуля спрацює


Чи працює це лише для класів логіки / моделі, чи я можу це використовувати також для делегата додатків?
Nicolas Miari

5

Мені вдалося вирішити цю проблему, очистивши конструкцію.

Головне меню -> Продукт -> Комбінація клавіш "Чистий чи клавіатурний": Shift+ Cmd+K


4

Станом на Swift 2.0, найкраща практика:

Додайте рядок @testable import MyAppу верхній частині файлу тестів, де «MyApp» є модуль Назва продукту вашої мети програми ( для перегляду в вашому додаток мішені установок для збірки). Це воно.

(Зверніть увагу, що назва модуля продукту буде таким самим, як ім'я цілі вашого додатка, якщо ім'я цілі додатка не містить пробілів, які будуть замінені підкресленнями. Наприклад, якщо моя ціль програми називалася "Весела гра", я напишу @testable import Fun_Gameв Поверхня моїх тестів.)


1

Вам потрібно додати процедуру, щоб компілятор посилався на точку входу, тому додайте файл main.swift, який у цьому випадку просто створює екземпляр вашого тестового файлу:

головна

PrimeNumberModelTests()

Потім компілюйте в командному рядку (я використовую El Capitan і Swift 2.2):

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

У цьому випадку ви отримаєте попередження: результат ініціалізатора не використовується , але програма компілює та виконується:

./PrimeNumberMain

CAVEAT: для простоти я видалив типи імпорту XCTest та XCTestCase.


1

Перевірте свої PrimeNumberModelTestsцільові налаштування.

Якщо ви не бачите PrimeNumberModel.swiftфайл у Build Phases/Compile Sources, додайте його.


Це не правильний спосіб зробити це, перевірте відповідь High6.
Diogo T

0

Отже, вам потрібно

  1. Імпортуйте зовнішні модулі, які ви хочете використовувати
  2. І переконайтеся, що у вас є правильні модифікатори доступу для класу та методів, які ви хочете використовувати.

У моєму випадку у мене був швидкий файл, який я хотів провести одиничний тест, а файл тестового модуля також був швидким класом. Я переконався, що модифікатори доступу були правильними, але заява

import stMobile

(скажімо, stMobile - це наше цільове ім'я)

все ще не працювало (я все ще отримував помилку "Немає такого модуля"), я перевірив свою ціль, і її назва справді була stMobile. Отже, я зайшов у "Налаштування збирання", під упаковкою, і знайшов назву модуля продукту, і чомусь це називалося St_Mobile, тому я змінив заяву про імпорт

import St_Mobile

(яка назва продукту ), і все працювало.

Отже, підводячи підсумки:

  1. Перевірте назву свого модуля продукту та використовуйте наведене нижче твердження про імпорт у своєму тестовому класі

    import myProductModuleName
  2. Перевірте правильність модифікаторів доступу (рівень класу та ваші методи).


0

Замість того, щоб вимагати явного імпорту, компілятор Swift неявно шукає .swiftmoduleфайли бібліотек Swift залежності.

Xcode може створити для вас швидкі модулі або зверніться до блогу railsware для інструкцій командного рядка swiftc.


0

Як зазначали @ high6 та @ erik-p-hansen у відповіді, наданій @ high6, це можна подолати, імпортувавши ціль для модуля, де знаходиться клас PrimeNumberModel, який, мабуть, є такою ж назвою, що і ваш проект у простому проекті .

Дивлячись на це, я натрапив на статтю Написати свій перший тест з одиниць у Swift на swiftcast.tv Клейтона Макілрата. Він обговорює модифікатори доступу, показує приклад тієї ж проблеми, що у вас є (але для ViewController, а не файл моделі), і показує, як імпортувати ціль і вирішити проблему модифікатора доступу, включивши в цільовий файл призначення, тобто вам не доведеться робити клас, який ви намагаєтесь перевірити загальнодоступним, якщо ви насправді не хочете цього робити.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.