I’m starting to write some commands with Swift Argument Parser, and I’m thinking ahead to unit testing. However, I’ve run into some questions about dependency injection when dealing with ParsableCommand
s.
For example, if I’m writing a command that does some work with FileManager
, that is likely something I would want to inject:
struct SomeCommand: ParsableCommand {
private let fileManager: FileManager
init(fileManager: FileManager = .default) {
self.fileManager = fileManager
}
func run() throws {
...
}
func someFunc() {
// some logic with file manager that we want to UT
}
}
However, the above code results in an error: Type 'SomeCommand' does not conform to protocol 'Decodable'. Type 'SomeCommand' does not conform to protocol 'ParsableArguments. Cannot automatically synthesize Decodable because FileManager does not conform to decodable
.
So this leads to the question – why is it that all stored properties of ParsableCommand
s must be decodable, and how do you work around this so that you can reliably unit test these commands?
One thing I tried which does alleviate the error is adding an Unparsed
property wrapper:
@propertyWrapper
struct Unparsed<Value>: Decodable {
var storage: Value?
init() { }
init(from decoder: Decoder) throws { }
var wrappedValue: Value {
get { storage! }
set { storage = newValue }
}
}
and then simply writing @Unparsed private var fileManager: FileManager
(then overloading the init
as well), but this seems less than ideal. How have people gone about this in the past?