Как импортировать файл 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'"    
}

Оба файла swift находятся в одном каталоге.



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

@ joseph.hainline У меня такая же проблема. Как это будет решаться? Я застрял сейчас.
Разработчик

Ответы:


131

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

Чтобы избавиться от:

Использование неразрешенного идентификатора 'PrimeNumberModel'

Мне нужно, чтобы importбазовый модуль в тестовом файле. В моем случае моя цель называется myproject, и я добавил, import myprojectи класс был распознан.


2
Это требует больше голосов. Ответы, предлагающие просто добавить файл .swift к цели теста, не совсем неправильны, но это не так, как должно быть
ниже

10
Но что делать с моим проектом под названием «Лига дикой природы», в котором есть место?
Алленлинли

59
Начиная с бета-версии 4, вам также необходимо убедиться в правильности настроек контроля доступа. Вам нужно будет подробно установить как класс, который вы тестируете, так и функции, которые вы тестируете в этом классе public. В противном случае XCTestCaseподкласс не сможет «увидеть» то, что вы пытаетесь проверить. Я потратил несколько часов на эту последнюю ночь :)
Эрик П. Хансен,

2
Если я не ошибаюсь, имя модуля продукта (в настройках сборки цели) не всегда совпадает с именем цели, и это имя модуля должно использоваться в importвыражении
csch

3
Если у цели Swift есть пробел в имени, вы можете импортировать его, заменив пробелы подчеркиванием в операторе импорта. «Мой 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() {
   }
}

Обратите внимание, что privatefileprivate) символы недоступны даже при использовании @testable.


Swift 1.x

Здесь есть две соответствующие концепции от Swift (как 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() {
   }
}

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

Я думаю, что это невозможно, по крайней мере, для текущей версии Swift.
Диого Т

Спасибо. И я обнаружил, что моя проблема заключалась в том, что файл swift не компилируется в цель теста с тестовыми примерами.
Метафокс

1
да, именно здесь я чувствовал себя не так - я не должен встраивать файл swift класса в цель теста. хороший пост в блоге! Спасибо.
Метафокс

1
Если у вас есть проект, созданный с помощью Xcode 5 или более поздней версии, и вы выбираете подход «общий доступ, импортировать целевой модуль», дважды проверьте имя модуля для вашей цели тестирования, поскольку оно может совпадать с главной целью. Если No such module <moduleName>в вашем тестовом примере вы получаете ошибку компиляции, вы можете проверить PRODUCT_MODULE_NAMEналичие цели теста. Отличный ответ Диого.
Крис

48

В документации сказано, что в Swift нет операторов импорта.

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

Просто используйте:

let primNumber = PrimeNumberModel()

2
Это сработало, но мне пришлось закрыть и снова открыть Xcode 6.0, чтобы класс наконец появился. Попробуйте очистить и построить проект.
user3344977 22.09.14

Это кажется новым (или проблемой) в последней бета-версии XCode 6.3, поэтому оператор import теперь необходим. Также в 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, вам не нужно импортировать быстрые файлы в той же цели. Наконец-то я заработал, добавив свой swift-файл как к обычной цели, так и к контрольной цели. Затем я использовал для проверки заголовок моста, чтобы убедиться, что мои файлы 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 решение импорта всего вашего модуля будет работать


Это работает только для классов логики / модели, или я могу также использовать его для Application Delegate?
Николас Миари

5

Я смог решить эту проблему, очистив мою сборку.

Главное меню -> Продукт -> Очистить или сочетание клавиш: Shift+ Cmd+K


4

Начиная с Swift 2.0, лучшая практика:

Добавьте строку @testable import MyAppв верхней части файла тестов, где «MyApp» - это имя модуля продукта для цели вашего приложения (отображается в настройках сборки цели вашего приложения ). Вот и все.

(Обратите внимание, что имя модуля продукта будет совпадать с именем цели вашего приложения, если только имя цели вашего приложения не содержит пробелов, которые будут заменены подчеркиванием. Например, если бы цель моего приложения называлась «Веселая игра», я написал бы @testable import Fun_Gameна вершина моих тестов.)


1

Вам нужно добавить подпрограмму для ссылки компилятора как на точку входа, поэтому добавьте файл main.swift, который в этом случае просто создает экземпляр вашего тестового файла:

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.
Диого Т

0

Итак, вам нужно

  1. Импортируйте внешние модули, которые вы хотите использовать
  2. И убедитесь, что у вас есть правильные модификаторы доступа для класса и методов, которые вы хотите использовать.

В моем случае у меня был файл swift, который я хотел пройти модульное тестирование, и файл модульного теста также был классом swift. Я убедился, что модификаторы доступа были правильными, но утверждение

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, который, вероятно, совпадает с именем вашего проекта в простом проекте. ,

Глядя на это, я наткнулся на статью Clayton McIlrath « Первый тестовый модуль в Swift» на swiftcast.tv. В нем рассматриваются модификаторы доступа, показан пример той же проблемы, с которой вы столкнулись (но для ViewController, а не файла модели), и показано, как импортировать цель и решить проблему модификатора доступа путем включения файла назначения в цель, что означает вам не нужно делать класс, который вы пытаетесь протестировать, публичным, если вы на самом деле не хотите этого делать.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.