Why Aren’t We Writing Unit Tests?

It works right? Why bother?
I wonder what happens when we put pink fluid in beakers?

It seems so innocent to just say “screw the tests!” and just keep trucking along, building out features and making things fly around on the screen. This is so painfully common for startups and newbie programmers. Why bother with testing the UI!? It changes so much anyways, it’s not even worth trying to write tests!

Of course the UI will constantly change. Businesses and Scrum masters want to keep iterating on an idea and make it better and better, so if it’s always going to keep on changing and getting more features, does that mean the tests from before even make any sense?

When the business is iterating over an idea, you’ll still need all previous functionality to always be working when you’re building out new features with each iteration. With this kind of logic, why wouldn’t you wan’t that safety blanket of unit tests to make sure this is always working? Otherwise, you’re just asking for regressions and features from past iterations to no longer work.

I will confidently and immediately say YES to building a foundation of unit testing. For those unaware, unit tests just test one small piece to make sure it’s always working.

This is best seen through example. Here’s a very straightforward function that adds two numbers together:

function addNumbers(x, y) {
return x + y;
}

To test this, we’d use something like expect and a framework like mocha or chai. For the purposes of this article, I’ll be using jest with jasmine since those come right out of the box with minimal configuration:

describe('addNumbers()', () => {
it('Adds two numbers together', () => {
expect(addNumbers(5,4)).toBe(9);
});
});

Great! Now we know every time we run this function, it will add these two numbers together. It didn’t take that much time to write up a quick test to make sure this works…

Business requirements have changed and we’re iterating on this little helper function we’ve made. It now has to accept up to 4 arguments and add them together now. no problem, we can refactor this to make that happen.

function addNumbers(a, b, c, d) {
return a + b + c + d;
}

Easy, right? That totally fulfills the requirements, but then…

TEST FAILED: expected 9 but received NaN

You probably shouldn’t add 5 + undefined. That returns NaN. If it weren’t for that test, you’d change up the function without even thinking of all the previous usage of it, and sadly, break the project. Your 2 minutes of test writing and running it saved you 5 to 10 minutes of debugging, and this is only for a simple addNumbers() example too.

Time’s your most valuable asset. Investing minutes today can save hours down the road. For those who aren’t used to writing tests, it might feel asinine, or even counter-productive to write up some tests. It’ll take more like 20 minutes instead of 2, and that’s most likely why lots of developers just skip writing unit tests. It takes time to learn how to write good tests, in addition to writing the tests themselves.

It’s like eating vegetables and eating healthy. Veggies aren’t really that tasty up front, and they’re not filling… But in the end, they’re really good for you. When you’re dragging your fork to stab that nasty piece of broccoli, stick it in your mouth and feel the sucky texture and taste… It doesn’t feel good. It feels empty and hollow. You want cheesy mashed potatoes and slabs of hot BBQ ribs, not chicken breast and broccoli.

NO WANT GREEN THING.

Your code works just fine and it meets the requirements of the product team. You know that you should probably write a test or two just to make sure your work is air-tight and solid, but… You still haven’t set up your testing framework and you have to learn all these boring libraries. It doesn’t feel good and you keep seeing FAILED across your terminal. You want to push your wonderfully working code live, not write tests.

The next time you eat your veggies, it gets a little easier. Sure, it can still be a bit of a struggle. Maybe you try something a little different, like cauliflower, or asparagus and things start to get a little bit better since you’re finding what’s normal about veggies.

You just finished up a new feature and you start writing up tests, it still a struggle, but you’ve been experimenting and have read enough documentation to have a pretty good idea of what you’re doing and what’s normal about testing.

Before you know it, you’ve eating a ton of clean food and veggies, and you’re losing weight and feeling great. Eating veggies is no longer a chore, it’s just something that you just do at every meal because you know it’s the right thing to do. It’s become a lifestyle for you, not a chore.

You’ve written hundreds of tests and without even thinking about it, you write tests for every feature and bug fix you make. It’s not a chore. It’s just something you start doing because you’ve engrained it into a habitual practice for yourself. Hell, sometimes you even write the test before you start coding and get into some Test Driven Development practices.

Learning how to write unit tests for your code just isn’t the most fun thing to do, but after so long, you get into it, and you can push your code up to production with confidence and certainty. Your fingers don’t just hover over the ENTER key, afraid something catastrophic might happen. You just push, and deploy, and have peace of mind that everything you’ve done will work.

PROBLEM: My project is already huge

It may seem like a problem that the project is already large and has zero tests, but in reality, it isn’t. Unit tests alone are very small and only test to make sure one or two little things work at a time.

All you have to do is get started with writing your first test.

You don’t need to test your gigantic codebase. Start with little pieces that can be tested and aren’t too ingrained. If that’s not the case, find a feature or bug to work on that can be testable.

After writing your first couple of tests, it’s just like the analogy from before — the first will feel a little weird, but it’ll get easier over time.

How do I get started?

Most likely, the biggest barrier to entry for those getting themselves acquainted to unit testing is getting your testing framework and tooling set up.

Luckily in the land of Javascript, testing tools are aplenty, and some like Jest don’t require much configuration to get started. For the most part, a straightforward npm install jest --save-dev will get you started.

Of course, nothing is one size fits all in the world of development, so here’s a few JS testing frameworks for you to check out:

  • Jest — This is my personal favorite because it offers snapshot testing, and my current work + self-owned projects are React based, and Jest works excellent with React (and Enzyme!).
  • Mocha — Another excellent and lightweight testing framework.
  • Jasmine — A behavior driven development framework for JS that doesn’t need a DOM. Jest actually uses Jasmine’s syntax and is included, but you can always use it piecemeal should you choose to do so.
  • Chai — Assertion library for Node and the Browser. The syntax is a little different than you’d see in Jasmine, but at the end of the day, they do the same thing.
  • Ava — An exciting and new library for testing which runs all of your tests concurrently. Extremely fast, and very powerful, now utilizing all the goodies of Babel 7.
  • QUnit — If you’re still in regular DOM manipulation land with jQuery, QUnit is excellent for testing out any DOM manipulation tests to make sure your JS is doing all the right things.

For those who are more Python oriented, My only experience with unit testing in Python is Nose, which I have enjoyed.

One Test is Better than Zero Tests

If you’ve set up your first framework and script to get your testing framework firing away, now it’s time to write that first test!

Start with something small, whether it’s a small utility function, or just making sure one of your views is rendering without crashing the process. It can be as simple as adding two numbers together, or making sure a class has been added or removed from an element.

Even if you have just one test, that’s better than zero, and you’re on the road to making your application stable, less bug free, and setting the foundation for adding new tools like Continuous Integration, which will prevent you from pushing broken code to production and save yourselves a bunch of time and headaches from fixing live bugs on production.