This is just a reminder from me to me. I constantly find myself searching through my previous projects trying to remember how to do this. Putting it in my blog might make it easier to find it in future.
Quite often, when writing test cases, I want to access resources that are not Swift code. For example, my 6502 project has a 6502 program that exercises every single 6502 instruction. At first, I was effectively hand compiling the program and embedding it into the Swift test cases. After a while I thought, wouldn’t it be better to properly write a 6502 program and use a real assembler to make a binary and then load it into the memory of the 6502? Well I could create the binary and then put it on disk and use Swift’s IO to load it into the CPU’s memory, but that required putting a file path into the test case code. It’s much better to include it as a bundle resource and then access the resource from the test case.
How to do that from Swift. Well adding the resource to the test bundle is easy. Add the resource to the target and then make sure it is copied during the “copy bundle resources” phase of the build.
The code needed to access that is quite simple, but if you don’t know how to do it needs at least five minutes of Googling. So here it is.
class SomeTest: XCTestCase { // Some stuff override func setUp() { super.setUp() let myBundle = Bundle(for: type(of: self)) let binaryFileUrl = myBundle.url(forResource: "coveragetest", withExtension: "bin") guard let binaryFileUrl = binaryFileUrl else { fatalError("Could not locate coverage test binary") } do { let program = try Data(contentsOf: binaryFileUrl) // Do something with the data } catch { fatalError("Could not read test coverage program") } } // All the test cases }
The only slightly non obvious line is the one that says
let myBundle = Bundle(for: type(of: self))
This line is the easiest way to locate the bundle of the test suite without specifying its name or location. It just gives you the bundle containing the test case class.