Testing is given much emphasis in the Ember.js community, and testing tools have showed steady progress to reduce the cost of writing tests of all types.
Lauren Tan wrote a great post about how Dependency Injection (DI) can be used to decouple a parent component from the internals of its child components. One of the gains of doing so is that the parent component becomes more focused and thus easier to test.
In this post, I’m doing something similar, although much simpler. I want to show you how to use DI in a simple helper function to make it easier to test.
Just your ordinary, run-of-the-mill function
Although the helper is an Ember (template) helper, the concepts could be very easily transferred to other frameworks, libraries and even languages.
I recently had to modify a normalizeText
helper function that looked
like this:
1 2 3 4 5 6 7 8 |
|
(I realize the above code does not handle a text value of undefined
or null
.
The real code does but I want to keep the code examples to the minimum necessary
to get my point across.)
Comparing objects to objects
Its test was quite simple and straightforward:
1 2 3 4 5 6 7 8 9 10 |
|
The problem with that test is that we compare two Handlebars.SafeString
instances (returned by Ember.String.htmlSafe
) which are different even if
the strings they wrap, their value, is the same:
1 2 3 |
|
We’re, however, interested in the equality of the strings. If only there was a
way to replace that pesky Ember.String.htmlSafe
call from the call site…
DI to the rescue
This is exactly what Dependency Injection can help us do. Instead of hard-coding that “sanitizer” function dependency, the function could take it as a parameter so that callers could inject it. Usually DI examples use (and thus inject) class names or object instances but it is important to realize that the injected param could be very “primitive”, like a simple function.
So here is how I rewrote the function:
1 2 3 4 5 6 7 8 9 10 11 |
|
Notice how easy ES2015 destructuring makes the assignment of the sanitizer function:
1
|
|
If no sanitizer
key was present in params
, then it will have a value of
Ember.String.htmlSafe
, the default behavior.
The call from the test can now override the default behavior of sending the
normalized text through Ember.String.htmlSafe
by passing in a “no-op”
sanitizer function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
We’re now comparing simple strings which place nicely with assert.equal
(with
===
), and our test now passes.
Non-testing benefits
Code modifications introduced for the sake of testing usually also improve the
non-testing aspect. Here, we made it possible to pass any function before we
return the normalized text. We could, for example, use this to replace the <p>
tags with <span>
s, if we so wish.