Humble Object Pattern in Swift

Alexey Kuznetsov
Dec 8, 2015 · 3 min read

Why is UI testing so hard? Because the framework usually creates the UI objects for us, and we only fill in the blanks. It is expensive or impossible to construct all UI elements needed in a test. The Humble Object pattern is a way to test the logic of UI objects.

How can we make code testable when it is too closely coupled to its environment? We extract the logic into a separate easy-to-test component that is decoupled from its environment.

Massive View Controller

The problem begins with a massive view controller. Historically, OS X separated mediating and coordinating controllers.

The mediating controllers together with the Cocoa Bindings technology were responsible for the data flow between view and model objects. The coordinating controllers were used to get several objects together for a specific task. They could respond to delegation and action messages, manage object life cycles, and establish a connection between objects.

The last sentence basically screams the violation of the single responsibility principle. The massive view controller problem appeared in OS X and got only worse in iOS.

iOS doesn’t support Cocoa bindings. The roles of mediating and coordinating controllers merged together leading to the Extremely Massive View Controller problem.

Whichever solution for deflating the massive view controllers is chosen—doesn’t matter. What’s important is that in the end the view controller should have only one role—controlling its view.

UIView–UIViewController Fusion

A view controller has a strong coupling to its view. Therefore, after all the irrelevant roles have been extracted from it, a view controller can be perceived as just a view. To some degree, a view controller is basically a view decorator providing the lazy-loading mechanism.

The outside world can just tell it to show some data and doesn’t have to know about the UIKit-specific details of presenting it. All labels, text fields, and image views are encapsulated inside a view controller, and only strings and images are exposed.

What’s left in the view controller is a simple mapping of values it receives from the outside to the UI elements of the view it controls. The view controller becomes very humble.

The Clean Architecture

To make a view controller humble, all irrelevant roles have to be extracted away from it. For the purpose of testing the UI, it doesn’t matter how exactly it is done. However, one can turn to the existing, well-known techniques for separating concerns.

The one that stands out is called The Clean Architecture with its derivative in the iOS world called VIPER. This approach summarizes what other well-known architectures have in common, where the business logic, the presentation logic, and the delivery mechanism should go.

The example below uses the Clean Architecture terms for naming objects.

Example

The example shows how a GPS tracking app could present the track summary.

The data for the presentation is originally prepared by an interactor object implementing the specific use case, the one of showing track summary.

How exactly the TrackSummaryInteractor gets the result data is unimportant for the UI testing example. It could work with some track repository to find the needed track and get only the required data. When the work is done, it notifies its output with the simple result data structure.

All presentation logic—converting timestamps and distances to strings—is implemented by a presenter object.

Being a use case’s output, the TrackSummaryPresenter converts the received data to a form that is ready to be used in UIView, but without any UIKit-specific details. Like the use case’s output, the presenter’s output is expressed in a protocol, so it becomes trivial to test the presentation logic.

All that’s left for the view controller is set the prepared values to the relevant UI elements.

This, very last, part is not covered by tests. But it is left so humble, so trivial, that it can be verified just by looking at it. There’s still a chance that a mistake will be made here, but it’s brought to a minimum.

In the end, all the parts are composed together:

Conclusion

The UI objects often end up having a lot of logic. This logic is hard to test because we don’t have control over the API and the lifecycle of the UI elements. The Humble Object pattern can be applied to extract the logic from the UI and test it independently. While doing so, the Clean Architecture can be taken as an example of a strict role separation.

Related Articles

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store