यूनिट टेस्ट के अंदर कोड बंडल संसाधनों को क्यों नहीं खोज सकते?


183

कुछ कोड मैं इकाई परीक्षण के लिए संसाधन फ़ाइल लोड करने की आवश्यकता है। इसमें निम्न पंक्ति शामिल है:

NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];

ऐप में यह ठीक चलता है, लेकिन जब यूनिट टेस्टिंग फ्रेमवर्क द्वारा चलाया जाता है तो pathForResource:यह शून्य हो जाता है, जिसका अर्थ है कि यह पता नहीं लगा सकता है foo.txt

मैंने यह सुनिश्चित कर लिया है कि कॉपी बंडल संसाधनfoo.txt में शामिल है इकाई परीक्षण लक्ष्य के चरण का निर्माण, तो यह फ़ाइल क्यों नहीं मिल सकती है?

जवाबों:


316

इकाई परीक्षण दोहन अपने कोड चलता है, अपने इकाई परीक्षण बंडल है नहीं मुख्य बंडल।

भले ही आप परीक्षण चला रहे हों, आपका आवेदन नहीं, आपका आवेदन बंडल अभी भी मुख्य बंडल है। (संभवतया, यह आपके द्वारा परीक्षण किए जा रहे कोड को गलत बंडल खोजने से रोकता है।) इस प्रकार, यदि आप इकाई परीक्षण बंडल में संसाधन फ़ाइल जोड़ते हैं, तो मुख्य बंडल को खोजने पर आपको यह नहीं मिलेगा। यदि आप उपरोक्त लाइन की जगह लेते हैं:

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *path = [bundle pathForResource:@"foo" ofType:@"txt"];

तब आपका कोड उस बंडल को खोजेगा जो आपकी इकाई परीक्षण कक्षा में है, और सब कुछ ठीक हो जाएगा।


मेरे लिए काम नहीं करता है। फिर भी बिल्ड बंडल और टेस्ट बंडल नहीं।
क्रिस

1
@ क्रिस सैंपल लाइन में मैं मान रहा हूं कि selfमुख्य बंडल में एक क्लास है, न कि टेस्ट केस क्लास। [self class]अपने मुख्य बंडल में किसी भी वर्ग के साथ बदलें । मैं अपना उदाहरण संपादित करूंगा।
बेंज़ादो

@benzado बंडल अभी भी वही (बिल्ड) है, जो सही है मुझे लगता है। क्योंकि जब मैं स्वयं या AppDelegate का उपयोग कर रहा हूं, तो दोनों मुख्य बंडल में स्थित हैं। जब मैं मुख्य लक्ष्य के बिल्ड चरणों की जाँच करता हूँ तो दोनों फाइलें अंदर होती हैं। लेकिन मैं मुख्य और परीक्षण बंडल के बीच रन टाइम के दौरान अंतर करना चाहता हूं। कोड जहां मुझे बंडल की आवश्यकता है वह मुख्य बंडल में है। मुझे निम्नलिखित समस्या है। मैं एक png फ़ाइल लोड कर रहा हूँ। आम तौर पर यह फ़ाइल मुख्य बंडल में नहीं होती है क्योंकि उपयोगकर्ता इसे सर्वर से डाउनलोड करता है। लेकिन एक परीक्षण के लिए मैं परीक्षण बंडल से एक फ़ाइल का उपयोग करना चाहता हूं बिना इसे मुख्य बंडल में कॉपी किए।
क्रिस

2
@ क्रिस ने अपने पिछले संपादन में गलती की, और उत्तर को फिर से संपादित किया। परीक्षण के समय, ऐप बंडल अभी भी मुख्य बंडल है। यदि आप एक संसाधन फ़ाइल को इकाई परीक्षण बंडल में लोड करना चाहते हैं, तो आपको bundleForClass:इकाई परीक्षण बंडल में एक वर्ग के साथ उपयोग करने की आवश्यकता है । आपको अपने यूनिट टेस्ट कोड में फ़ाइल का पथ प्राप्त करना चाहिए, फिर पथ स्ट्रिंग को अपने अन्य कोड के साथ पास करना चाहिए।
बेंज़ादो

यह काम करता है लेकिन मैं एक रन-तैनाती और एक परीक्षण-तैनाती के बीच अंतर कैसे कर सकता हूं? इस तथ्य के आधार पर कि यह एक परीक्षण है मुझे मुख्य बंडल में एक वर्ग में परीक्षण बंडल से एक संसाधन की आवश्यकता है। यदि यह एक नियमित 'रन' है, तो मुझे मुख्य बंडल से संसाधन की आवश्यकता है न कि परीक्षण बंडल की। कोई उपाय?
क्रिस

78

एक स्विफ्ट कार्यान्वयन:

स्विफ्ट 2

let testBundle = NSBundle(forClass: self.dynamicType)
let fileURL = testBundle.URLForResource("imageName", withExtension: "png")
XCTAssertNotNil(fileURL)

स्विफ्ट 3, स्विफ्ट 4

let testBundle = Bundle(for: type(of: self))
let filePath = testBundle.path(forResource: "imageName", ofType: "png")
XCTAssertNotNil(filePath)

बंडल आपके कॉन्फ़िगरेशन के लिए मुख्य और परीक्षण पथ खोजने के तरीके प्रदान करता है:

@testable import Example

class ExampleTests: XCTestCase {

    func testExample() {
        let bundleMain = Bundle.main
        let bundleDoingTest = Bundle(for: type(of: self ))
        let bundleBeingTested = Bundle(identifier: "com.example.Example")!

        print("bundleMain.bundlePath : \(bundleMain.bundlePath)")
        // …/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Agents
        print("bundleDoingTest.bundlePath : \(bundleDoingTest.bundlePath)")
        // …/PATH/TO/Debug/ExampleTests.xctest
        print("bundleBeingTested.bundlePath : \(bundleBeingTested.bundlePath)")
        // …/PATH/TO/Debug/Example.app

        print("bundleMain = " + bundleMain.description) // Xcode Test Agent
        print("bundleDoingTest = " + bundleDoingTest.description) // Test Case Bundle
        print("bundleUnderTest = " + bundleBeingTested.description) // App Bundle

7 | | 8 | Xcode 6 में 9, एक इकाई परीक्षण बंडल पथ में हो जाएगा Developer/Xcode/DerivedDataकी तरह कुछ ...

/Users/
  UserName/
    Library/
      Developer/
        Xcode/
          DerivedData/
            App-qwertyuiop.../
              Build/
                Products/
                  Debug-iphonesimulator/
                    AppTests.xctest/
                      foo.txt

... जो Developer/CoreSimulator/Devices नियमित (गैर-इकाई-परीक्षण) बंडल पथ से अलग है :

/Users/
  UserName/
    Library/
    Developer/
      CoreSimulator/
        Devices/
          _UUID_/
            data/
              Containers/
                Bundle/
                  Application/
                    _UUID_/
                      App.app/

यह भी ध्यान दें कि इकाई परीक्षण निष्पादन योग्य है, डिफ़ॉल्ट रूप से, एप्लिकेशन कोड के साथ जुड़ा हुआ है। हालांकि, यूनिट टेस्ट कोड में केवल टेस्ट बंडल में लक्ष्य सदस्यता होनी चाहिए। आवेदन कोड में केवल आवेदन बंडल में लक्ष्य सदस्यता होनी चाहिए। रनटाइम के दौरान, इकाई परीक्षण लक्ष्य बंडल को निष्पादन के लिए एप्लिकेशन बंडल में इंजेक्ट किया जाता है

स्विफ्ट पैकेज मैनेजर (एसपीएम) 4:

let testBundle = Bundle(for: type(of: self)) 
print("testBundle.bundlePath = \(testBundle.bundlePath) ")

नोट: डिफ़ॉल्ट रूप से, कमांड लाइन swift testएक MyProjectPackageTests.xctestटेस्ट बंडल बनाएगी । और, swift package generate-xcodeprojवसीयत एक MyProjectTests.xctestपरीक्षण बंडल बनाएगी । इन अलग-अलग टेस्ट बंडलों के अलग-अलग रास्ते हैंइसके अलावा, विभिन्न परीक्षण बंडलों में कुछ आंतरिक निर्देशिका संरचना और सामग्री अंतर हो सकते हैं

किसी भी मामले में, .bundlePath और .bundleURLवर्तमान में macOS पर चलाए जा रहे परीक्षण बंडल का पथ लौटाएगा। हालांकि, Bundleवर्तमान में उबंटू लिनक्स के लिए लागू नहीं किया गया है।

इसके अलावा, कमांड लाइन swift buildऔर swift testवर्तमान में संसाधनों की नकल के लिए एक तंत्र प्रदान नहीं करते हैं।

हालांकि, कुछ प्रयासों के साथ, स्विफ्ट पैकेज मैंगर को मैकओएस एक्सकोड, मैकओएस कमांड लाइन और उबंटू कमांड लाइन वातावरण में संसाधनों के साथ उपयोग करने के लिए प्रक्रियाओं को स्थापित करना संभव है। एक उदाहरण यहाँ पाया जा सकता है: 004.4'2 SW देव स्विफ्ट पैकेज मैनेजर (SPM) रिसोर्स Qref के साथ

इसे भी देखें: स्विफ्ट पैकेज मैनेजर के साथ यूनिट टेस्ट में संसाधनों का उपयोग करें

स्विफ्ट पैकेज मैनेजर (एसपीएम) 4.2

स्विफ्ट पैकेज मैनेजर PackageDescription 4.2 स्थानीय निर्भरता के समर्थन का परिचय देता है ।

स्थानीय निर्भरता डिस्क पर पैकेज हैं जिन्हें सीधे उनके रास्तों का उपयोग करके संदर्भित किया जा सकता है। स्थानीय निर्भरताएँ केवल रूट पैकेज में दी जाती हैं और वे पैकेज ग्राफ़ में एक ही नाम से सभी निर्भरताएँ ओवरराइड करती हैं।

नोट: मैं उम्मीद करता हूं, लेकिन अभी तक परीक्षण नहीं किया है, कि एसपीएम 4.2 के साथ निम्नलिखित जैसा कुछ संभव होना चाहिए:

// swift-tools-version:4.2
import PackageDescription

let package = Package(
    name: "MyPackageTestResources",
    dependencies: [
        .package(path: "../test-resources"),
    ],
    targets: [
        // ...
        .testTarget(
            name: "MyPackageTests",
            dependencies: ["MyPackage", "MyPackageTestResources"]
        ),
    ]
)

1
स्विफ्ट 4 के लिए भी, आप बंड का उपयोग कर सकते हैं (के लिए: प्रकार के (स्वयं के))
रॉकेट गार्डन

14

स्विफ्ट स्विफ्ट 3 के साथ सिंटैक्स self.dynamicTypeको हटा दिया गया है, इसके बजाय इसका उपयोग करें

let testBundle = Bundle(for: type(of: self))
let fooTxtPath = testBundle.path(forResource: "foo", ofType: "txt")

या

let fooTxtURL = testBundle.url(forResource: "foo", withExtension: "txt")

4

पुष्टि करें कि संसाधन परीक्षण लक्ष्य में जोड़ा गया है।

यहां छवि विवरण दर्ज करें


2
परीक्षण बंडल में संसाधनों को जोड़ने से परीक्षा परिणाम काफी हद तक अमान्य हो जाता है। आखिरकार, एक संसाधन आसानी से परीक्षण के लक्ष्य में हो सकता है, लेकिन ऐप लक्ष्य में नहीं, और आपके परीक्षण सभी पास होंगे, लेकिन ऐप आग की लपटों में बदल जाएगा।
dgatwood

1

यदि आपकी परियोजना में कई लक्ष्य हैं, तो आपको लक्ष्य सदस्यता में उपलब्ध विभिन्न लक्ष्य के बीच संसाधनों को जोड़ने की आवश्यकता है और आपको नीचे दिए गए आंकड़े में दिखाए गए चरणों के अनुसार अलग-अलग लक्ष्य के बीच स्विच करने की आवश्यकता हो सकती है

यहां छवि विवरण दर्ज करें


0

मुझे यह सुनिश्चित करना था कि यह सामान्य परीक्षण चेकबॉक्स सेट किया गया था यह सामान्य परीक्षण चेकबॉक्स सेट किया गया था

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.