At least some folks on the Swift team have said that @testable
is a "hack" and a "stopgap", and it doesn't sound like it's believed that making small tweaks to its behavior would improve the testing story around Swift.
I tend to agree with that. Components should be designed with testability in mind from the outset, rather than depending on hypothetical and unsafe language hacks to break guarantees that you've explicitly asked for in your code.
As mentioned above, the final
keyword allows the compiler to make certain decisions about the code it generates for the types and its methods based on the fact that you've declared it that way. That's an innate characteristic of the type, independent of how or from where it is imported. The technical roadblock is that methods simply wouldn't be dispatched correctly; when the compiler knows a class is final
, it can generate method calls without using dynamic dispatch because it knows they'll never be overridden. If you tried to import such a class, subclass it, and override a method, some calls just wouldn't work.
The compiler can't guarantee correctness while also helping you avoid designing a solution to this problem. Having a protocol and a final class in your business logic module, with a test-fake implementation of the protocol in your test module, is the right way to do this. You can even put some of the implementation into the protocol so that it's shared by the real class and the fake, and you only have to override what you need.