Practical Dynamic Type, Part 2: Testing

Keehun Nam
Aug 27, 2018 · 4 min read

Last year, our software developer Chris Sessions wrote a helpful article about practical usage of Dynamic Type. This short follow-up addresses one primary concern: Unit Testing. Since adjustsFontForContentSizeCategory cannot be unit tested, let’s make our own!

Here is an example of a view that incorporates Dynamic Type features using Chris’s FontMetrics wrapper from Part 1:

That is not unit–testable. What are we going to do about it?

  1. Our FontMetrics can observe the system’s Dynamic Type size change and read the new size.
  2. Crucially, we can also ask UIFont to use our own contentSize instead of the system’s when calling its preferredFont()

With those two key components, we can implement our own Dynamic Type but with our own writable preferredContentSizeCategory.

So what does that actually look like?

Here is how I arrived at this new code:

First, FontMetrics needs to use its own source of UIContentSizeCategory and not the system’s preferredContentSizeCategory. This is reflected in lines 41–45. Notice that assigning a new value posts a notification for all observers of FontMetric’s ContentSizeCategoryDidChange.

Secondly, this is not demonstrated in this article, but I changed over any references in my app’s code of the system-provided UIContentSizeCategoryDidChange notification to our own: FontMetricsContentSizeCategoryDidChange

Third, in case that the user changes his or her Dynamic Type setting on their device while the app is running, FontMetrics observes for those changes and then changes its own sizeCategory to match the new system setting for a seamless experience (which then posts a notification). We never want the user to notice that anything is different than how they expect system settings to work.

Fourth, now that sizeCategory behaves exactly as we would like, we request UIFontMetrics.default.scaledFont() to use our ContentSizeCategory instead of the system’s own. This can be seen in lines 59, 69, 87, and 100.

Fifth, although this wasn’t strictly necessary, I created a static constant called default so that calling FontMetrics.default would always return the same instance. This is akin to NotificationCenter.default or UIDevice.current. It just helps make users of FontMetrics keep their code clean-looking and bug-free (by avoiding accidentally using a different instance of FontMetrics. This also meant that any references to FontMetrics() in my app was replaced with FontMetrics.default.

Basically, we’ve recreated the mechanism behind UIContentSizeCategoryDidChange and made our own writable version of preferredContentSizeCategory.

To take advantage of our new FontMetrics wrapper, we must update Hal9000 as well!

Notice that we aren’t using `adjustsFontForContentSizeCategory = true` anymore, but now it’s unit testable!

Trade Offs

Onto unit tests!

Note that while we’re measuring the same subject.dialog.font.pointSize three times, we’ll get a different result as we’re changing FontMetric.default.sizeCategory before each measurement!

With this power, there are many things we can choose to do with it. Here are just some ideas:

  • Unit test Auto Layout with many different font sizes, especially complex layouts involving UIStackViews that changes axis according to its contents
  • Write (and be able to test!) custom controls and views that implement Dynamic Type features
  • Design unit-testable interfaces which reduce white spaces at higher levels of Dynamic Type size (e.g. a form with vertical white space between fields that get closer together as the text gets bigger instead of the fields getting further apart)
  • Sleep better at night knowing that any regression of Dynamic Type features will be caught! 🎉
Hal9000 is passing!

So… What’s next?

Here, you can download the Xcode project and run the tests yourself!

More Resources

Livefront

Thoughts from the Livefront team

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