NSURL to file path in test bundle with XCTest

后端 未结 8 1617
栀梦
栀梦 2020-12-23 18:35

I am trying to write an iOS app using TDD and the new XCTest framework. One of my methods retrieves a file from the internet (given a NSURL object) and stores it in the user

8条回答
  •  误落风尘
    2020-12-23 19:14

    Swift 5.3

    Note: Swift 5.3 includes Package Manager Resources SE-0271 capabilities which can be used with application bundle and test bundle resources.

    Resources aren't always intended for use by clients of the package; one use of resources might include test fixtures that are only needed by unit tests. Such resources would not be incorporated into clients of the package along with the library code, but would only be used while running the package's tests.

    Swift 4, 5:

    let testBundle = Bundle(for: type(of: self))
    guard let fileURL = testBundle.url(forResource: "imageName", withExtension: "png") 
      else { fatalError() }
    
    // path approach
    guard let filePath = bundle.path(forResource: "dataName", ofType: "csv")
      else { fatalError() }
    let fileUrl = URL(fileURLWithPath: filePath)
    

    Bundle provides ways to discover the main and test paths for your configuration:

    @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
    

    The Xcode URL will be in Developer/Xcode/DerivedData something like ...

    file:///Users/
      UserName/
        Library/
          Developer/
            Xcode/
              DerivedData/
                App-qwertyuiop.../
                  Build/
                    Products/
                      Debug-iphonesimulator/
                        AppTests.xctest/
                          imageName.png
    

    ... which is separate from Developer/CoreSimulator/Devices URL

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

    Also note the unit test executable is, by default, linked with the application code. However, the unit test code should only have Target Membership in just the test bundle. The application code should only have Target Membership in the application bundle. At runtime, the unit test target bundle is injected into the application bundle for execution.

    Swift Package Manager (SPM) 4:

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

    Note: By default, the command line swift test will create a MyProjectPackageTests.xctest test bundle. And, the swift package generate-xcodeproj will create a MyProjectTests.xctest test bundle. These different test bundles have different paths. Also, the different test bundles may have some internal directory structure and content differences.

    In either case, the .bundlePath and .bundleURL will return the path of test bundle currently being run on macOS. However, Bundle is not currently implemented for Ubuntu.

    Also, command line swift build and swift test do not currently provide a mechanism for copying resources.

    However, with some effort, it is possible to set up processes for using the Swift Package Manger with resources in the macOS Xcode, macOS command line, and Ubuntu command line environments. One example can be found here: 004.4'2 SW Dev Swift Package Manager (SPM) With Resources Qref

提交回复
热议问题