ฉันจะนำเข้าไฟล์ 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 คุณไม่จำเป็นต้องนำเข้าเมื่อทั้งสองไฟล์มีเป้าหมายเดียวกัน การทดสอบที่น่าเศร้ามีเป้าหมายที่แตกต่าง ทางออกหนึ่งที่เป็นไปได้คือการทำคำสั่งนำเข้าโดยใช้ yourModule / PrimeNumberModel
Alex Reynolds

@ joseph.hainline ฉันกำลังเผชิญกับปัญหาเดียวกัน จะแก้ไขได้อย่างไร? ตอนนี้ฉันติดอยู่
นักพัฒนา

คำตอบ:


131

ฉันมีปัญหาเดียวกันกับXCTestCaseไฟล์ของฉันแต่ไม่ได้อยู่ในไฟล์โครงการปกติ

เพื่อกำจัด:

การใช้ตัวระบุที่ไม่ได้แก้ไข 'PrimeNumberModel'

ฉันต้องการimportโมดูลฐานในไฟล์ทดสอบ ในกรณีของฉันเป้าหมายของฉันถูกเรียกว่า 'myproject' และฉันเพิ่มimport myprojectและชั้นเรียนได้รับการยอมรับ


2
สิ่งนี้ต้องการ upvotes มากขึ้น คำตอบที่แนะนำให้เพิ่มไฟล์. swift ไปยังเป้าหมายการทดสอบนั้นไม่ผิดอย่างแน่นอน แต่ไม่ใช่วิธีที่ควรทำ
ต่ำกว่า

10
แต่จะทำอย่างไรกับชื่อโครงการ "Wildlife League" ของฉันซึ่งมีพื้นที่ว่างในนั้น?
allenlinli

59
เริ่มต้นด้วย Beta 4 คุณจะต้องตรวจสอบให้แน่ใจว่าการตั้งค่าการควบคุมการเข้าถึงของคุณนั้นถูกต้อง คุณจะต้องอธิบายให้ชัดเจนทั้งชั้นเรียนที่คุณกำลังทดสอบและฟังก์ชั่นที่คุณกำลังทดสอบในชั้นเรียนpublicนั้น มิฉะนั้นXCTestCaseคลาสย่อยจะไม่สามารถ "เห็น" สิ่งที่คุณพยายามทดสอบ ผมเสียเวลาไม่กี่ชั่วโมงเมื่อคืนที่ผ่านมานี้ :)
เอริคแฮนเซนพี

2
ถ้าฉันไม่เข้าใจผิดชื่อของโมดูลผลิตภัณฑ์ (ในการตั้งค่าการสร้างเป้าหมาย) ไม่เหมือนกับชื่อของเป้าหมายเสมอและเป็นชื่อของโมดูลที่ควรใช้ในimportคำสั่ง
csch

3
หากเป้าหมาย Swift มีช่องว่างในชื่อคุณสามารถนำเข้าได้โดยแทนที่ช่องว่างด้วยขีดล่างในคำสั่งนำเข้า "My Swift Class" กลายเป็น "My_Swift_Class"
Cin316

70

UPDATE 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 ที่นี่ (ในฐานะ 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() {
   }
}

มีวิธีใดในการเปลี่ยนการควบคุมการเข้าถึงเริ่มต้น ฉันมีกรณีตลก ๆ ที่มันเคยใช้โดยไม่มีตัวแก้ไขสาธารณะดีแล้วฉันย้ายกรณีทดสอบไปรอบ ๆ มันหยุดทำงานทันทีอีกต่อไป
Metaphox

ฉันคิดว่ามันเป็นไปไม่ได้อย่างน้อยสำหรับรุ่นปัจจุบันของ swift
Diogo T

ขอบคุณ และฉันพบว่าปัญหาของฉันคือไฟล์ swift ไม่ได้ถูกสร้างขึ้นเพื่อทดสอบเป้าหมายด้วยเคสทดสอบ
Metaphox

1
ใช่นั่นคือสิ่งที่ฉันรู้สึกผิด - ฉันไม่ควรสร้างไฟล์ class swift ลงในเป้าหมายของกรณีทดสอบ โพสต์บล็อกที่ดี! ขอบคุณ
Metaphox

1
หากคุณมีโครงการที่สร้างด้วย Xcode 5 หรือใหม่กว่าและคุณกำลังเลือกวิธี "การเข้าถึงสาธารณะนำเข้าโมดูลเป้าหมาย" ให้ตรวจสอบชื่อโมดูลสำหรับเป้าหมายการทดสอบของคุณอีกครั้งเพราะอาจเหมือนกับเป้าหมายหลัก หากคุณได้รับNo such module <moduleName>ข้อผิดพลาดในการรวบรวมในกรณีทดสอบคุณอาจต้องการตรวจสอบPRODUCT_MODULE_NAMEเป้าหมายการทดสอบ คำตอบที่ดี Diogo
คริส

48

ในเอกสารอธิบายว่าไม่มีข้อความสั่งการนำเข้าใน Swift

ป้อนคำอธิบายรูปภาพที่นี่

เพียงใช้:

let primNumber = PrimeNumberModel()

2
สิ่งนี้ใช้ได้ แต่ฉันต้องปิดและเปิด Xcode 6.0 อีกครั้งเพื่อให้คลาสปรากฏขึ้นในที่สุด ลองทำความสะอาดและสร้างโครงการเช่นกัน
user3344977

ดูเหมือนว่าจะเป็นเรื่องใหม่ (หรือปัญหา) ใน XCode 6.3 รุ่นเบต้าล่าสุดดังนั้นคำสั่งการนำเข้าจึงจำเป็นในตอนนี้ นอกจากนี้ยังมีคำสั่งการนำเข้าใน Swift เพื่อนำเข้าโมดูล
Augunrik

ตามเอกสารที่ให้มาตารางนี้ที่มี "คำสั่งการนำเข้าไม่มี" เกี่ยวข้องกับกรณี "นำเข้าจากเป้าหมายเดียวกัน" ในกรณีของ XCTests คุณใช้เป้าหมาย (ทดสอบ) ที่แตกต่างกันดังนั้นให้สังเกตส่วน "Importing External Frameworks" ของบทความมีตารางอื่น: กรอบภาษาใด ๆ -> นำเข้าสู่ Swift -> จำเป็นต้องนำเข้า "FrameworkName"
Igor Vasilev

หากคุณพบปัญหาในเครื่องมือแก้ไขบ่อยครั้งที่มีเป้าหมายทดสอบที่ไม่มีคลาสรวมอยู่ ดังนั้นคุณอาจสร้างค่าปรับที่รันได้ของคุณ แต่หากหนึ่งในเป้าหมายใดมีปัญหาก็ยังคงแสดงข้อผิดพลาด หากคุณเลือกหนึ่งในเป้าหมายอื่นเหล่านั้นมันจะไม่อนุญาตให้คุณรวบรวม
Joel Teply

34

ตรวจสอบเป้าหมายการเป็นสมาชิกของ PrimeNumberModel.swift ในเป้าหมายการทดสอบของคุณ


1
โปรดเพิ่มสิ่งนี้เป็นความคิดเห็น
4dgaurav

8
บุคคลนี้ทำไม่ได้เขาต้องการตัวแทนเพิ่มอีก 9 คนเพื่อทำเช่นนั้น (ในขณะที่เขียน)
AlbertEngelB

1
เป้าหมายคืออะไร?
ผู้ใช้

ขอบคุณสิ่งนี้ใช้ได้สำหรับฉัน คลิกที่ไฟล์คลาส ตรวจสอบแท็บแรกของคอลัมน์ผู้ตรวจสอบทางด้านขวา ส่วนที่สองคือ "Target Membership" ตรวจสอบให้แน่ใจว่าได้เลือกเป้าหมาย / ผลิตภัณฑ์ที่คุณต้องการรวมไว้ในชั้นเรียนแล้ว
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()
}

อย่างที่คุณเห็นไม่มีความจำเป็นในการนำเข้า หวังว่านี่จะช่วยได้


ขอบคุณ! ยังคงได้รับสิ่งใหม่ทั้งหมดจากในสวิฟท์
เฟลิเป้

5

ตามแอปเปิ้ลคุณไม่จำเป็นต้องนำเข้าไฟล์ที่รวดเร็วในเป้าหมายเดียวกัน ในที่สุดฉันก็สามารถทำงานได้โดยการเพิ่มไฟล์ swift ลงในทั้งเป้าหมายปกติและเป้าหมายการทดสอบ จากนั้นฉันก็ใช้ส่วนหัว bridging สำหรับการทดสอบเพื่อให้แน่ใจว่าไฟล์ ObjC ของฉันที่ฉันอ้างถึงในส่วนหัว bridging ปกติของฉันนั้นพร้อมใช้งาน วิ่งได้อย่างมีเสน่ห์ตอนนี้

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 ได้หรือไม่?
Nicolas Miari


4

ตั้งแต่ Swift 2.0 แนวทางปฏิบัติที่ดีที่สุดคือ:

เพิ่มบรรทัด@testable import MyAppที่ด้านบนของไฟล์ทดสอบโดยที่ "MyApp" เป็นชื่อโมดูลผลิตภัณฑ์ของเป้าหมายแอปของคุณ (สามารถดูได้ในการตั้งค่าการสร้างเป้าหมายแอป ) แค่นั้นแหละ.

(หมายเหตุว่าชื่อโมดูลผลิตภัณฑ์ที่จะเป็นเช่นเดียวกับชื่อเป้าหมายของแอปเว้นแต่ชื่อเป้าหมายของแอปมีช่องว่างซึ่งจะถูกแทนที่ด้วยขีด. ตัวอย่างเช่นถ้าเป้าหมาย app ของฉันถูกเรียกว่า "เกมสนุก" ผมเขียน@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

ในกรณีนี้คุณจะได้รับคำเตือน: ผลลัพธ์ของ initializer ไม่ได้ใช้แต่โปรแกรมคอมไพล์และสามารถใช้งานได้:

./PrimeNumberMain

ถ้ำ: ฉันลบประเภทการนำเข้า XCTest และ XCTestCase เพื่อความเรียบง่าย


1

ตรวจสอบ .. ของคุณ PrimeNumberModelTestsการตั้งค่าเป้าหมาย

หากคุณไม่เห็นPrimeNumberModel.swiftไฟล์ใน Build Phases/Compile Sourcesให้เพิ่มเข้าไป


นี่ไม่ใช่วิธีที่ถูกต้องตรวจสอบการตอบสนอง High6
Diogo T

0

ดังนั้นคุณต้อง

  1. นำเข้าโมดูลภายนอกที่คุณต้องการใช้
  2. และให้แน่ใจว่าคุณมีตัวดัดแปลงการเข้าถึงที่ถูกต้องในคลาสและวิธีการที่คุณต้องการใช้

ในกรณีของฉันฉันมีไฟล์ swift ฉันต้องการทดสอบหน่วยและไฟล์ทดสอบหน่วยก็เป็นคลาสที่รวดเร็ว ฉันทำให้แน่ใจว่าตัวดัดแปลงการเข้าถึงถูกต้อง แต่คำสั่ง

import stMobile

(สมมติว่า stMobile เป็นชื่อเป้าหมายของเรา)

ยังคงไม่ทำงาน (ฉันยังคงได้รับข้อผิดพลาด 'ไม่มีโมดูลดังกล่าว') ฉันตรวจสอบเป้าหมายของฉันและชื่อของมันคือ stMobile แน่นอน ดังนั้นฉันไปที่การตั้งค่าการสร้างภายใต้บรรจุภัณฑ์และพบชื่อโมดูลผลิตภัณฑ์และด้วยเหตุผลบางอย่างนี้เรียกว่า St_Mobile ดังนั้นฉันจึงเปลี่ยนคำสั่งการนำเข้าของฉัน

import St_Mobile

(ซึ่งเป็นชื่อโมดูลผลิตภัณฑ์ ) และทุกอย่างทำงานได้

ดังนั้นเพื่อสรุป:

  1. ตรวจสอบชื่อโมดูลผลิตภัณฑ์ของคุณและใช้คำสั่งนำเข้าด้านล่างในคลาสทดสอบหน่วยของคุณ

    import myProductModuleName
  2. ตรวจสอบให้แน่ใจว่าตัวดัดแปลงการเข้าถึงของคุณถูกต้อง (ระดับชั้นเรียนและวิธีการของคุณ)


0

แทนที่จะต้องการนำเข้าอย่างชัดเจนคอมไพเลอร์ Swift จะค้นหา.swiftmoduleไฟล์ของห้องสมุด Swift ที่ขึ้นต่อกันโดยปริยาย

Xcode สามารถสร้างโมดูลที่รวดเร็วสำหรับคุณหรือดูที่บล็อก railswareswiftcสำหรับคำแนะนำสำหรับบรรทัดคำสั่ง


0

เนื่องจาก @ high6 และ @ erik-p-hansen ชี้ให้เห็นในคำตอบที่ได้รับจาก @ high6 สิ่งนี้สามารถเอาชนะได้โดยการนำเข้าเป้าหมายสำหรับโมดูลที่มีคลาส PrimeNumberModel ซึ่งอาจเป็นชื่อเดียวกับโครงการของคุณในโครงการง่าย ๆ .

ในขณะที่มองสิ่งนี้ฉันเจอบทความเขียนการทดสอบหน่วยแรกของคุณใน Swiftบน swiftcast.tv โดย Clayton McIlrath มันกล่าวถึงตัวดัดแปลงการเข้าถึงแสดงตัวอย่างของปัญหาเดียวกันที่คุณมี (แต่สำหรับ ViewController มากกว่าไฟล์แบบจำลอง) และแสดงวิธีการนำเข้าเป้าหมายและแก้ไขปัญหาตัวดัดแปลงการเข้าถึงโดยการรวมไฟล์ปลายทางในเป้าหมายความหมาย คุณไม่ต้องทำให้ชั้นเรียนคุณพยายามทดสอบในที่สาธารณะเว้นแต่ว่าคุณต้องการทำเช่นนั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.