How I learned to love unit testing

Stephen Griffiths on August 30, 2018

Flashback to 2012. When I arrived at Village as a 19-year-old young man with a lot to learn*, I would have broadly categorized myself as a "hacker"... [Read Full]
markdown guide
 

In college, I always heard about unit testing and how important it was, but it wasn't taught.
In my first job as a software engineer, we had an extremely Legacy system and the company didn't want to "waste" time on going back and making tests for things.
At my second one, a startup, I constantly asked for it (since I honestly didn't know what it actually was, I was afraid to just.... Do it), and was told to leave it on the back burner until we got the product out.
At both jobs, I know that we constantly ran into the same bugs, that would've easily gotten caught. I knew there was a solution, but didn't feel I had the permission or knowledge to make it happen.

Recently I've been working on my own project and wanted to tackle the daunting task of Unit Tests. It is extremely easy to get lost in the weeds. You start by seeing a tutorial with the most basic of tests, like assert.equals(1+1, 2), and you think you can handle it all. And then you do a little more research and see people talking about mocks, spies, stubs, test runners vs test frameworks. It's so easy to get overwhelmed and want to give up.

Truly, starting simple is extremely important. There are SO many things that you can sufficiently test with a basic assert.equals(myVar, 5). Let all of the bells and whistles come as they're needed.

 

Sadly common story. I tried for several years to unsuccessfully convince the leadership at a consulting agency that they didn't need to sell unit tests separately, but they were a core feature of the development itself and that we should always write it them for all our code.

But no, to this day (10+ years after I started, 5 years after I left) that company still considers unit tests to be an extra, something people do at other places.

Gladly at the next place there were some unit tests, but still at a poor level. People didn't think of them at all, most of them were actually not unit tests but massively slow monsters. They pretended their SOLID principles were all that were needed to make code easily testable, and .. it wasn't. More like the opposite in many cases.

Nowadays there's little I do without unit tests, and require them in all projects I'm working with. I consider it more like you don't really know your stuff works before you can prove it with unit tests. You don't always need a lot of them, but you still need to have them.

The recent trends in unit testing tools and methods getting better are just amazing, with Python the mock library is simply incredible and most dbs and such come with mocking libraries too, and things like snapshot testing are making so many things easier to test.

Unfortunately still there are still several common areas that are annoyingly difficult to test, you'd think that by now websites were super easy to test but often this is not the case. Also in the gamedev world you will find automated tests to be almost non-existent, but the gamedev world tends to move quite slowly overall so it's not that surprising.

 

I bet this is a common story. I had the same exact thing happen to me. Jobs where tests weren't of any importance so I just never learned. I had to force myself and be the example for the team.

 

Same story here with at the end not being able to use TDD.

I used to develop naturally close to the TDD way. I would create a function, test every scenario manually and once it worked, move on to the next bits of code.

When TDD became popular and I heard of it (many years ago), I was super excited and wanted to try that, only to be told we could not do that.
At the time, processes and technologies were strictly controlled in the industry I worked in (finance).
I gave up pushing for it.

Then, a few years later, I became tech support in a different company and industry and I saw they were using unit tests so at least I can say I've read test units, even if I've never created them.

 

I'm starting to develop a few tools for my company and I'm getting into it and that's true that's it's so easy to get lost and it's better to start small.

But I would say it is the same as everything in programming.

After a few years not following what's new in Javascript, I'm learning all about Node.js, Express, Vue, React, Graphql, Apollo etc ...
And that's only related to javascript!

 

One of the frictions to unit tests is the language and environment.

Unit testing in C++ is not fun. I don't think it will ever be fun.

Unit testing in C# using Visual Studio, NUnit (or xUnit.net), and NCrunch was joy wrapped in "squeee!" of delight.

Unit testing in D is superfluous, since D has proper contract programming. (Unit tests are nothing more than contract programming for languages that lack contract programming constructs as part of the core language.)

And then there is always the danger of someone sticking integration tests into the unit test mix. Integration tests have their place, too... but not commingled in with the unit tests. Unit tests are like working with quarks, hadrons, leptons, and atoms. Whereas integration tests are like working with girders, bricks, mortar, electrical wiring, plumbing.

 

When building smaller APIs, I sometimes find that my end-to-end tests and unit tests for my controllers tend to overlap a lot. Since I usually don't have many middlewares, or the middlewares are out-of-the-box from libraries which are already well-tested, the two different kinds of tests usually end up doing the same thing which is a lot of duplication and mocking of services.

Am I assuming something wrong here or is the duplication really good/necessary?

 

It's quite likely your controllers are doing too much stuff.

Your controllers really only aught to be

  1. Parse & validate request
  2. Call some kind of service to do something useful
  3. Return a HTTP response according to 2.

If they do more, you probably should be refactoring logic out of your controller. Note how if you have a broad "service" later injected into your controller, you only need to mock the one thing

Another possibility is your end to end tests are too exhaustive. Google for Martin Fowler's test pyramid, the number of e2es should be small. Test the key business cases and then unit test everything else. This should give you enough confidence your system works and keeps your test suite from taking a long time to execute.

 

Another thing to mention here: if something goes wrong in your application which (obviously) wasn't covered by any test then try to add a unit test for this particular case. If that isn't an option then you may write an integration test. If that isn't viable either than you are allowed to write and e2e test.

Why? Because unit tests are the cheapest tests you can run. Everything else is exepnsive in various ways.

You should keep in mind that if writing a unit test seems to be really hard your code may need some refactoring. This of course always sounds trivial but it's sometimes a hard thing to grasp at first. But it will pay off because you'll learn a lot. Just try!

 

That's a great point Ravern, and I feel you - I've had the same thing. I think that you don't need to unit test things that are:

  • Features of an underlying dependency
  • Basic CRUD pipelines which don't alter or transform the data

But anything in your solution which is unique or original could be unit tested. For example:

  • Do you have data transfer objects which construct on top of data from another source? Test that they instantiate with the expected values
  • Do you parse/process/transform API data? Unit test your assumptions about that

Straightforward API projects often do some of the above.

That said, unit testing is a helper, not a law! Test what it's helpful to test. Your end-to-end testing sounds like it provides a lot of value, and perhaps in many cases that's all you need!

 

I'm gonna try and keep it brief...

At the time of writing this, I can say I wholeheartedly share the same sentiment as you when it comes to writing tests. A few years ago, my arrogance and lack of knowledge made me perceive writing unit/integration tests as a way to confine yourself from future changes and extremely difficult to do, due to the level of verbosity you need to get to your coverage goals.

Fast-forward to last year: Since then I had matured as a developer and had embraced ES6, and had the fortunate luck of building components that are used by thousands of ppl every day.

With that ego-boost, I set a wild coverage target (100%) for a couple of those components and, needless to say, your ego begins to fade and flaws surface as you write your test cases. What I thought would take a week to test fully (just one of the components) actually turned into a sleepless month-long refactoring, modularizing, and testing exercise. More importantly, writing those tests taught me more about JS and my own writing style than anything else.

Obviously, my opinion on authoring tests code has completed changed since then, and your post really resonated with me, so thanks for that.

Btw, check out the testing time on this: reddit.com/r/BeAmazed/comments/9bl...

 

Good read, I had some laughs :)

I actually JUST recently had that same "saw the light" moment with unit tests so now I feel good about writing them.

Refactoring 3x duplicated code across our app into one class and unit testing every code path. A job well done :)

 

In my early young career, I had not the chance to do unit tests and back then it was not a trending skill. After a return in school, Ill have a class this semester that covers unit tests and I can't wait to learn more about it. I too find it overwhelming, hopefully that course will help me.

During my last internship in a big corp, they had many IT solution and despite their gigantic size, their wasn't a single unit test. While waiting to learn about unit tests, I am reading "Building Maintainable Software" published at O'Reilly. There is a lot of useful tips on how to make consistant and short unit of codes so you can better test them and maintain them. I highly recommend this reading.

 

Nice read, thanks for sharing. I will need to break up my big subroutines but don't see how yet... who wants to have a look at my python code? 🤓

 

Great! Maybe you could post it on codereview.stackexchange.com/ or perhaps in a new post here? Let us know!

 

I used to be a big contributor to that community. It warms my heart to see a link to it out in the wild.

 

hi there I posted a code review question but it's about logging, not unit testing :) codereview.stackexchange.com/quest...

 

Thanks for the tip! I'll craft a demo of the code I currently use because I would reveal too much personal information. Once posted I'll add the link here!

 

Great article about the journey to embrace testing. I’m also advocating testing at any possible occasion and praise the benefits. But it I think your article shows a very important point: It’s mostly not easy. Everyone of us wants to write prod code and it‘s good to tell people „yep, we were there, too“ instead of „you’re doing it wrong!“

 

Integration tests are always better than unit tests. It cover much larger code-base chunk (except corner cases, where is to hard to reproduce some logic) and yes, they're more expensive, but it's in our duty to make it cheaper with modern instruments like Testcontainers and similar.

So I think only viable case for unit-tests is corner cases.

blog.usejournal.com/lean-testing-o...

 

Thank you for share your interest. i want to recommend you to learn free or paid Software testing and unit testing. you should join JanBask Training for Unit Testing. if you have any questions then you can discuss here regarding Unit Testing. i will try to resolve. you can also get the free tutorial at JanBask training.

 

Great post ! It illustrates the fact that TDD is first & foremost a DESIGN tool, not a testing tool ! Testing is only a happy consequence. 🙂

 

Nice article.

I totally agree with you, and I unit test my side projects, always, because I know how much you get having them! Especially when you do refactoring.

But, the sad thing is that at work, in my company, we don't write unit tests, because everything is about the money and time, because time is money, and unit tests takes time. I worked on many projects, and every time I ask "Should I write unit tests", the answer is "No", or "We'l decide later", or similar. We are working for clients, that care more about when the product will be completed, then about the quality of the product.

In my opinion, the main problem of unit tests is that people can not see the result of them at the beginning (and clients can't see why they are important at all). At the end, unit tests save money and time, and clients should know it!

 

At my workplace I have been unsuccessful in convincing people to unit test and it is not about getting product out the door. It is a resistance to change. Overcoming the "I've been programming for 15 years without it" is difficult. Even when I wrote the infrastructure, gave training, pages examples etc just getting people to write a spec can be exasperating.

 

I feel like you might benefit from this one @jess

As the post indicates, learning to love unit tests is a journey.

 

Thanks Ben! It's true. If you're like me, you can be convinced into seeing the value of tests, but not into liking them. Learning to like them is a journey and probably something you have to own for yourself! :) Best of luck @jess , may your days be full of rad tests and radder code.

 
 

Once you get unit tests it changes your world!

 

wow! Thanks for sharing your journey!

Personally, I'm still on the road to not hating uniting testing. and this article helped. :}

 

I love that it comes from an honest place. Would love to see more teams adding a fun touch to it

 

Great on job on telling the story of your journey through the test-driven approach! Very enjoyable read that could help a lot of people understand the usefulness of this methodology.

code of conduct - report abuse