I LOVE TESTING.
Everyone loves the excitement of a new project. There is planning to do, new technology to work with, and the green field of possibilities gets everyone excited.
We all agree that with this new project that we are going to do things right. We set lofty goals around test driven development (TDD) and 100% code coverage while we develop our testing strategy. As the project kicks off, we slowly have to let go of TDD and pair programming to meet a few deadlines and before we know it, tests are falling behind to meet the stringent deadlines coming down from management.
Reality begins to sink in… I LOVE the IDEA of testing, especially you testing YOUR code. Mine is probably fine.
The reality is that testing is hard. Testing takes a lot of time. As we write unit tests, we begin writing code to mock out our backend services and before we know it, the mocks feel like they have a life of their own warranting a separate project. As developers, we become frustrated with the entire process and begin to do the minimum shallow tests to squeak through a code review. Then, as we begin to refactor our code to improve it, a massive number of tests begin to fail and it requires hours of combing through tests and mocks to figure out what changed and why everything is failing. To make matters worse, the tests take a long time to run, and on each iteration we have to execute the entire suite of tests to get to the test we are trying to fix.
Discouraged developers face a grim reality, either comment out the failing tests to meet the deadline, or spend the evening/weekend working through the massive list of failures.
Jest: A Better Way
There has to be a better way...
Jest might just be the testing tool you’ve been waiting for. It was created by the Facebook team in order to to improve the testing process. It was originally created in 2015, but wasn’t received well, even at Facebook. It was difficult to configure, confusing, and not intuitive. In 2017 a new version was released that promised zero configuration and an easy to learn syntax.
The test output is a lot more readable and understandable using Jest. The challenge with using other tools like Karma is having to dig through very large stack traces trying to locate the test(s) that failed, and why. The test output for Jest is very readable and makes finding errors a breeze.
Another great feature about Jest is that code coverage is built in and easy to use. Developers save time as the output is inline and not in an html file that needs to be opened/refreshed after every run. Further, the code coverage output can be piped through istanbul or other similar filters to comply with various CI tooling. Running tests with coverage is as simple as `jest --coverage`.
Jest has several CLI features that make running tests even easier. Jest has a powerful CLI file matching feature to execute only the tests that you need to. For example, say I only want to run tests with the name customer in the filename. I can execute `jest customer` and only those files matching the string “customer” will be selected for testing. In addition, jest has a watch mode that extends this filtering even further while providing several other powerful tools. It’s as simple as executing `jest --watch`.
From the watch interface, a developer can run all tests, just failed tests, filter test by filename using a regex, and filter tests by test name using a regex. This make focusing on just failing tests or specific tests in a functional area very easy. No more waiting for all the passing tests to run before getting to the failed tests. Focus on what is important.
Migrating to Jest
One big concern developers have about bringing in a new testing framework is having to learn a whole new setup and syntax. If you’ve been using Karma and Jasmine in your test suite, which is the default for an Angular CLI project, then Jest will be very familiar. The Jest testing globals are based on Jasmine globals, so for most developers, it looks exactly the same. In addition, there is little to no need to refactor existing tests to work with Jest because they work as is.
The biggest difference between Jest and other testing frameworks is snapshot testing. Snapshots allow you to capture a “snapshot” of serializable values and compare them to previous values. This simplifies how we write our tests and allows us to analyze how state has changed over time. The serializable values can include JSON objects, HTML, or text, to name a few. Snapshot testing compares the expectation to a stored snapshot and creates a snapshot if one doesn’t already exist. It performs a diff comparison on the snapshot and produces an output similar to a git diff. The snapshots are stored in a __snapshots folder and the files become part of the code review process.
You might be asking, what are the benefits of using snapshots? The biggest reason is our mocks can be minimal or even elimited. You don’t have to create and maintain complex JSON objects to compare our unit test results to. Imagine storing the expected result of your unit test and receiving a warning anytime it changes. The same can be done for HTML. Since component views should be deterministic, e.g., if given the same inputs, they should produce the same output each time, then we can simplify our component tests and get better coverage by using snapshots.
Jest and snapshot testing is here to change how we think about tests, and reduces the amount of time it takes to deliver quality tests. Updating and fixing tests after refactors becomes much easier, and developers begin to enjoy writing tests. Take Jest for a spin and see if you don’t agree.
You can reach me at:
Follow me on Twitter: @JesseS_BrieBug
To learn more about marbles and the supported syntax, checkout:
Check out the GitHub repo for this blog:
Check out my talk at ng-Conf on NgRx Jest Testing:
Slides from my talk: