IOS VIPER: How protocol helps in Unit Testing?

2.7k Views Asked by At

I am little confused with the benefit of protocols in VIPER architecture. I understand that DI (Dependency Injection) achieved via protocols and helps avoid direct dependency between objects - I Agree.

But i am looking at a real benefit from usage perspective, an example may be - especially how protocols help benefit in unit testing (testing the Interactor portion).

Can't we achieve the same via method Callback's using blocks? Hope someone can help me understand from usage perspective with some example

Cheers

2

There are 2 best solutions below

4
On BEST ANSWER

Using a callback, e.g. from the Interactor to the Presenter, can make it harder to test the Presenter.

When writing tests for how the Presenter processes input (sent from the Interactor) your test would have to call some method on the Presenter that would cause the Presenter to make a call on the Interactor, which would cause the Interactor to send data to the Presenter.

By having the Presenter implement a protocol defined by the Interactor, your test can just directly call the appropriate input method on the Presenter.

As far as declaring protocols, I practice TDD in the style of mock roles, not objects (http://www.jmock.org/oopsla2004.pdf). The protocols help provide a better abstraction by focusing on what the object does (its role), not how it does it.

Protocols, on their own, are of little value for the unit tests. Your unit tests will provide test doubles (http://martinfowler.com/bliki/TestDouble.html) for the dependencies of the system under test. Even if you expose dependencies as concrete classes you can still create test doubles for your test.

In Objective-C, you can use a mocking library, such as OCMock (http://ocmock.org), or OCMockito (https://github.com/jonreid/OCMockito), to create stubs, spies, or mocks of the concrete class.

In Swift, you could create your test doubles by subclassing each of the concrete classes used as dependencies.

In short, protocols are not used to ease unit testing, but to describe at a higher level of abstraction, what the application does.

Here is an example of how having the abstract protocols were beneficial after the fact:

I created a protocol to represent the actions a user could perform on a screen, e.g. ProfileUserActions, that had actions such as changeName, and changeAddress. The Presenter implemented ProfileUserActions, and the View accepted a ProfileUserActions as a dependency. When the user tapped a button on screen, the View would send the appropriate message to its userActions object.

When I wanted to add analytics, I was able to create a new, independent ProfileAnalytics class which also implemented ProfileUserActions. I inserted the analytics object between the View and the Presenter, which allowed the app to capture analytics, without having to modify either the View or the Presenter.

0
On

By using a protocol it is easier for you to swap out an implementation in your VIPER structure. For example, you might have an interactor that is working with a class that is writing to the filesystem. You don't want to be testing the filesystem in your unit tests so instead if you put the filesystem write operations in your interactor behind a protocol you can then replace the filesystem write operations with an in-memory implementation.

As for a protocol on the interactor itself, I think it pays to be a bit more pragmatic about your choice. If it's easy to build your interactor for the test and it doesn't cause any side effects as part of testing then there's probably no need for the protocol. On the other hand, if you have to create a number of other dependencies then it might pay to have the interactor conform to a protocol so that you can more easily fake the output you get from the interactor.