Writing testable code

dmk12
3 min readOct 12, 2017

--

Silence of the Specs

Writing testable code

I recently read a book called “Testable JavaScript” by Mark Ethan Trostler. It is an excellent book that contains many valuable insights, and I recommend it highly. However, I found the title to be unnecessarily limiting — as it describes universal coding principals and good practices that can be applied to any programming language, not just JavaScript, it should be titled “Testable Code”.

Below is a list of key points that I took away from Mark’s book. This list contains answers to most frequently asked questions on how to write testable code.

What should a unit test actually test?

A unit test tests the smallest amount of code possible — a method, and nothing else. Good unit tests test only one method; they should not rely on other methods being called or used. At the bottom level of a single unit test, a single assertion should rely on only the method being tested and any mocks, stubs, or doubles needed for the method to work.

What is the smallest amount of code possible?

In other words, what is the “unit” in “unit test”? To answer this we need to explain the termcyclomatic complexity”.

Cyclomatic complexity is a measure of the number of independent paths through your code, i.e if/else or any other conditional. Each independent path should be tested, therefor the “unit” in “unit test” is each possible independent path through the tested method.

Image credit: Alex Norris http://webcomicname.com/post/163716486209

Cyclomatic complexity should be reduced where possible to make the code easier to test.

What is “command query separation”?

Commands are functions that do something (setters); queries are functions that return something (getters). Separate them to avoid convolution and make the code easier to test.

Ideally each method in your code should do a single thing — return a value (query) or set a value (command).

Fan-in, fan-out

Fan-out is a measure of the number of modules or objects your function directly or indirectly depends on. Try to keep fan-out to a minimum to avoid tightly coupled code.

Fan-in is the measure of reuse of a function throughout the app. For common functions — the higher the better. For non-common, non-utility functions, or for higher levels of code abstraction, the lower the better.

Pure functions — why and how?

A pure function is a function where the return value is only determined by its input values, without side effects.

You should strive to make your functions as pure as possible in order to make the code easier to test. A pure function is self contained — it does not depend on any external values (zero fan-out), and is able to execute by relying purely on its arguments. A pure function has no side effects — it does not change any external values while executing.

You should strive to make you functions as close to pure as possible in order to make your code easier to test.

Code coverage

Less than 50% code coverage is a red flag; 60% to 80% code coverage is the sweet spot, and anything over 80% is gravy. The law of diminishing returns can apply to unit testing when trying to get unit tests above 80% coverage.

Mocks and stubs — what’s the difference?

Test doubles are mocks and stubs. Mocks are used for commands and stubs are used for queries.

Mock objects are used to verify that your function is correctly calling an external API. Tests involving mock objects verify that the function under test is passing the correct parameters (either by type or by value) to the external object. In the command query world, mocks test commands. In an event hub world, mocks test events being fired. E.g. — a mock class.

Stubs are used to return canned values back to the tested function. Stubs do not care how the external object’s method was called; stubs simply return a canned object of your choosing. E.g. — a stub http response.

— — — — — — — —

Happy testing!

--

--