Mocking Swift classes in unit-testing

Hello everyone!

At this moment I am working on creating an environment for unit-testing on my job, and it seems there is a lack of mocking libraries (like OCMock in Objective-C), which makes writing tests even harder. This problem, if I understand correctly, has own reasons, but the need to test Swift code still exists, so I would be happy to hear about your experience: how you write unit-tests, what approaches, libraries, tools you use, etc.

As for me, I see only two solutions: writing mocks manually and using SwiftyMocky. The first one seems to lead to boilerplate, the second one increases complexity of environment, including generated source files, adding scripts to start it, problems while working with pods, etc. In other words, now I have not found anything suitable enough :pensive:

Thank you in advance!

The third option is not to mock. Dynamic mocking libraries, in addition to not being compatible with Swift, are a complexity nightmare for any test suite of reasonable complexity. I also find they obfuscate the actual purpose of code and often lead to tests of the mocks rather than your real systems.

Instead, using actual dependency injection with default values allow for a flexible, realistic testing environment that also has the added benefit of requiring more flexible APIs. Of course, this doesn't mean covering all of your dependencies with protocols. Instead, use instances of the real types as much as you can, only abstracting things you can't otherwise test.

Hmm, can you please provide an example of this option? For instance, I need to test a view model that it calls expected methods of its view, how then should your view look like? Or if your object writes something in Keychain?

Here's a good tutorial:

1 Like

And here's a good framework:

1 Like

@Patrick_Gili has provided some good resources, though I take a less formal approach to injection and certainly don't use anything like Swinject. Instead, a simple approach of test inputs and outputs is almost always enough to verify correctness.

For instance, in you view model case, testing it calls the methods of another object is very fragile, both from an implementation and maintenance standpoint. Instead, testing that your view model reacts to outside changes appropriately and produces the changes necessary for the view would be another approach.

For the keychain or even writing to files, simply using the real thing would verify your behavior is correct. For instance, most keychain interaction is done through a wrapper of some kind. Initializing instances of your own types with instances of the wrapper (to allow for a separate keychain storage area than the real app) and verifying you get data in and out should verify your code is functioning correctly.

@Patrick_Gili thank you for the links you sent, I agree that this is a great tool to manage dependencies.

Sorry, it seems I do not quite understand what your approach is. How to verify reactions of my view model without checking what methods it calls? For instance, I need to test that the user taps a button and my view model starts refreshing. To check it, I have to be sure that it calls refresh() declared in some NetworkService protocol (view model's dependency), but this approach, if I get your point, is not good. But it does not produce anything instead of calling that method. How then would you test this case?