DEV Community

Cover image for How I learned to love unit testing
Ste Griffiths
Ste Griffiths

Posted on • Originally published at villagesoftware.co.uk

How I learned to love unit testing

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" (this once caused Johnny to visibly grimace, which – in hindsight – I can understand). I liked to sit at a computer and start writing the features. The design flowed from my fingers.

Unit tests, when explained to me, created a kind of physical revulsion; "Here is code that you have to write to prove that your code works"... but who tests the test tests?

I was introduced to "mocks" at the same time, which appeared to be a way of saying that "because it's impossible to run unit tests with real data, we must see how your code-which-tests-code runs on data which is not the real data". This did not seem like a useful thing to do.

The trifecta of testing pain was completed by attempts to encourage Test-Driven Development (TDD), which is to say "you may only write code which is either a failing unit test, or which makes a failing unit test pass" - i.e. write all of your unit tests up-front and then write the implementations.

These elements created such a confusion and sadness within me that I didn't do much (successful) unit testing in my early days of professional software development.

Home Simpson GIF - My life is ruined

To me, programming was, and forever should be fun! Software development is like construction, except with unlimited undo, unlimited materials, X-Ray vision, and tools made of unobtainium – you can make whatever you want in the blink of an eye and change it whenever you like. Programming is expressive, joyful, and satisfying. Unit testing, I believed, robbed me of these joys.

So how is it that today, unit testing is part of the fun for me?

*Sadly, the amount I have left to learn has only increased since that time

My first unit testing success

It's 2015. I was writing a game in my spare time for my own entertainment. In this game, spacecraft could form and disband fleets, but this feature was a mess. In playtesting, the fleets would fail to form, fail to disband, grow and shrink by accident... I needed some way to comprehensively test these code paths without playing through every option myself with a scientific rigour. It dawned on me that unit tests were actually the answer.

Source code of unit tests for some space ships

I had tasted the usefulness of unit tests. In this process, I even wrote a simple kind of mock; something that would provide objects for me to work with instead of user-entered data. Testing this project was a happy, easy experience because:

  • My project only worked with plain old .Net objects (no database connections or weird dependencies)
  • The classes under test had clear responsibilities

Testing showed loads of flaws in my implementation which I never would have caught by hours of manual testing. Suddenly, the code was clean, clear and under control! I also realised that my game logic was tightly-coupled to the user interface; tests wouldn't finish because they were waiting for user input. So I refactored the game object to accept a delegate for progressing the game; while the real game would use Console.Readline(), the tests could pass in a do-nothing delegate. I had unwittingly encountered and implemented inversion-of-control. Thanks testing!

Turning up the heat

Lifted by success with unit testing in the personal arena, I set about introducing tests to a troublesome project at Village. This project had code quality issues which the team was struggling to conquer.

We instituted a policy where anytime you fixed a bug, you had to write a unit test to prove that it was fixed and stays fixed! This was not always possible because we were integrating with Microsoft Office, and some of the office objects are very difficult to mock. But this encouraged us to:

  • Separate business logic from front-end-integration logic
  • Test all possible business logic
  • Make clearer class responsibilities

This project now has about 300 unit tests, and is a successful project which is in users' hands daily! This was a great chance to get more of our quickly expanding team on board with the benefits of unit testing.

Making it cool

Around this time, I also noticed that the cool kids on GitHub who had hundreds of NPM packages would proudly display automatically-generated badges on the front page of each project, proclaiming "___% coverage". They were game-ifying the proportion of lines of code covered by unit tests, and that appealed to me a lot!

Badges on the front page of a GitHub repo

Suddenly, unit testing was not just useful, it was cool.

Unit Tests Imbuing Beauty

Lately, we built a project which searches the contents of many different file types. The different search components were built in isolation and it wasn't practical to run a full-breadth test of the system with any regularity. This was an ideal place for unit testing, and the project came pretty close to Test-Driven Development.

  • The search provider follows the Factory pattern, with tests to ensure they always produced the expected search engine for the given file type.
  • The search engines follow the Strategy pattern, with tests to ensure that they read sample files correctly.
  • The search result models have tests as simple as checking the right defaults are always set on a new object, or that a search creates an appropriate description of what was searched for and how many results there were.

It is truly a thing of beauty.

Making a difference

Somewhere along the road, unit testing stopped being a burden, and started being a joy. What can you do to make this happen?

  • Start simple. I was overwhelmed as an enterprise coding newb to be introduced to testing, mocking, and TDD all at once. If you haven't done automated testing before, start with anything. It doesn't matter whether you use black-box or white-box, the right technique, or the right framework. Just test something!
  • Own it. Contrive a simple project which you can test. Or if you are an encourager, give such a project to your team for them to muse upon. Make it fun.
  • Learn structure. Unit testing goes hand-in-hand with object-oriented principles. These take time and experience, but as you improve in one, you improve in the other. One Big Subroutine is not testable at all, but a solution which follows object principles (which often begin to look like design patterns) will be very testable.
  • Make it cool. Yeah, this is a bit of an unknown. But let the advocates advocate. Let the culture bearers in your organisation pass this on as a fun enhancement, not as a burden. Don't hammer it home, but create an atmosphere where provable quality is rewarded, and if possible, gameified!

I hope this helps to encourage you about the benefits and accessibility of automated testing, particularly unit testing. If you have any questions or comments, hit me up on twitter @SteGriff, and if you want to take on an expert org to work with you or your project, talk to us @VillageSoftware!

Syndicated from Village Software

Geordie thumbs up

Latest comments (31)

Collapse
 
alediaferia profile image
Alessandro Diaferia

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.

Collapse
 
kell18 profile image
Albert Bikeev

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...

Collapse
 
nverinaud profile image
Nicolas Verinaud

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

Collapse
 
dusan100janovic profile image
Dušan • Edited

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!

Collapse
 
beginagain profile image
Todd Hogarth

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.

Collapse
 
stealthmusic profile image
Jan Wedel

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!“

Collapse
 
zeddotes profile image
zeddotes

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...

Collapse
 
jmplourde profile image
Jean-Michel Plourde

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.

Collapse
 
nateous profile image
Nate

Once you get unit tests it changes your world!

Collapse
 
makingloops profile image
Joe Petrakovich

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 :)

Collapse
 
moe64 profile image
Moe

wow! Thanks for sharing your journey!

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