Search code examples
iosswifttestingxctestcase

IOS tests interacting with Mac file system


So I'm playing around with swiftui XCTestCase. I have a bunch of tests that run and get that they are running in the simulator or on the device.

However - I now have a need to interact with the Mac I'm on - ie read and write to the Mac file system from the IOS tests - is it possible - as the test is running in the simulator.


Solution

  • XCTestCase has access to the local file system be design with some restrictions. For example:

    func testExample() throws {
        print("\(Bundle.allBundles)")
        print("\(Bundle(for: type(of: self)))")
    }
    

    This code will produce something like this:

    [NSBundle </Volumes/Extended/Archive/Xcode_11.6.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/CoreServices/CoreGlyphs.bundle> (not yet loaded), NSBundle </Users/dive/Library/Developer/CoreSimulator/Devices/9CDF771B-204F-45B9-AAC3-6036AB7B117D/data/Containers/Bundle/Application/5DE85255-F202-4BAB-871A-7C20C2DB37D9/TestingBundles.app> (loaded), NSBundle </Users/dive/Library/Developer/CoreSimulator/Devices/9CDF771B-204F-45B9-AAC3-6036AB7B117D/data/Containers/Bundle/Application/5DE85255-F202-4BAB-871A-7C20C2DB37D9/TestingBundles.app/Frameworks> (not yet loaded), NSBundle </Users/dive/Library/Developer/Xcode/DerivedData/TestingBundles-exdmnsfatmhbztarzgjvvlwwpoan/Build/Products/Debug-iphonesimulator/TestingBundles.app/PlugIns/TestingBundlesTests.xctest> (loaded)]
    
    NSBundle </Users/dive/Library/Developer/Xcode/DerivedData/TestingBundles-exdmnsfatmhbztarzgjvvlwwpoan/Build/Products/Debug-iphonesimulator/TestingBundles.app/PlugIns/TestingBundlesTests.xctest> (loaded)
    

    As you can see, these paths are related to the DerivedData directory. As a result, you cannot use relative paths to the directory with your project or tests.

    Also, you can use FileManager directly. It inherits the same environment and has access to the local file-system as well. For example:

    func testExample() throws {
        let manager = FileManager.default
        print(try manager.contentsOfDirectory(atPath: ("~/" as NSString).expandingTildeInPath))
    }
    

    It will produce something like this:

    /Users/USER_NAME/Library/Developer/CoreSimulator/Devices/9CDF771B-204F-45B9-AAC3-6036AB7B117D/data/Containers/Data/Application/0D16C376-80A6-4DAE-B435-2FEF7F08A83A
    

    Note, that because of the environment, it points to the home directory of the user within a simulator.

    As a workaround, we are using a Shared user directory to share such data. There is a "Run Script" in the Test Pre-Actions that copies it:

    enter image description here

    Then we access it from XCTestCase like this:

    try manager.contentsOfDirectory(atPath: "/Users/Shared/TestData")
    

    It is not ideal and, perhaps, there are some other solutions. But it works fine and has a predictable behaviour.