Unit test for experienced beginners

Into: the part you can skip…

Once my team and I started working on a new framework, came the opportunity and the obligation to it the best way. This meant adopting new habits that include changes in the development process, including unit testing.

The challenge was from one side to learn how to write a unit test, and this was the first goal of this post. But from the other side, the challenge was how to change and adopt the “unit testing” mindset. for this, I gathered the second part of the post.

Some of the stuff mentioned here is from homework we have done, some from experience, and few are common sense. So probably, later on, there will be plenty of changes and adaptation along the way.

Link to the presentation unit test slides.

Unit testing isn’t about finding bugs… It documents your design and makes it easier to refactor and expand your code while retaining a clear overview of each component’s behavior.

However, a suite of bad unit tests is immensely painful: it doesn’t prove anything clearly, and can severely inhibit your ability to refactor or alter your code in any way.

js-unit-testing-guide

What’s a unit?

  • Whatever is public (method or action)

One of the biggest misconceptions in unit testing is this notion that, when you test a class, you should cover each and every method in it with unit tests… Just make them public – not a big deal! – and be done with it.

Well, that’s a horrible approach… By exposing methods that you would otherwise keep private, you reveal implementation details. And by coupling tests to those implementation details, you get a fragile unit test suite.

Vladimir Khorikov: Unit testing private methods

What’s to check

  • Every returned value
  • Every exception
  • State change
  • 3rd party calls (API, database, …)

Testing code is not like production-code: design it to be dead-simple, short, abstraction-free, flat, delightful to work with, lean. One should look at a test and get the intent instantly…

… we don’t have ‘headspace’ for additional complexity…

Readable

  • Understand behavior from the test list
  • Naming is critical
  • Short & Simple interaction
  • Only necessary setups
  • Return readable error message
  • From trivial to edge cases
  • Bug test in a different place (the crazy zone), linked to the bug
  • Test review before code review (Face to face)

Maintainable

  • DRY: define each unit and test suite
  • Short & Simple interaction
  • Independent
  • Isolated: Minimize dependencies
  • Only necessary setups
  • Each test covers one behavior
  • Each behavior covered in one test
  • DRY: don’t retest the same thing

Trustworthy

  • Won’t pass when needs to fail and vice versa
  • No flickering tests
  • No “know” test failures
  • Don’t comment test – It will scare us forever
  • Avoid logic inside the test
  • Avoid leaking domain knowledge to tests

A stub is an object that holds predefined data and uses it to answer calls during tests. It is used when we cannot or don’t want to involve objects that would answer with real data or have undesirable side effects…

Mock is an object that registers calls they receive. In the test assertion, we can verify on Mocks that all expected actions were performed.

Andre Pratama: Testing Mock vs Stub

Guidelines:

  • Avoid code pollution
  • Support configuration variables (like different environments)
  • Mock as less as possible
  • Stub as much as you can
  • A single level of abstraction

How to

This section meant to understand how we can adapt and get used to working in a testable approach.

  • Split each requirement into small unit tasks
  • If you can – TDD
  • Know what you are testing
  • Plan your tests before coding
  • Write tests in a logical order
  • Make each test fail
  • Create negative tests
  • Read the code coverage
  • Cover also edge cases
  • Code review starts by reading the test – face to face

Conclutions:

I presented this post to the team (as a slideshow). Afterward showed them a well-known unit on code, and gone over the unit test, showing how the written test answer the points mentioned here. Then we looked inside some tests, understanding where they lied, and didn’t test whatever they meant. Later on, we opened the code coverage to see how much we can learn about the code by seeing the lines the test didn’t cover: logic that hadn’t been tested, dead code, edge cases and so.

“but,” one cried, “Its a totally different way to work”. The other added, “the development will take much longer”. The third mentioned the quote from above: “suite of bad unit tests is immensely painful” adding, “How can we guarantee that we are not making bad tests and inhibit ourself”.

“Yup”, I answered, “We definitely will make bad tests”, I promised, “At least at the beginning. But, later on, we all will be on a totally different level as programmers, with a much more clear and organized development process, and with a way more reliable and stable product”, I paused for a few moments, then added “And here is my part… To make this become the truth”

Credits and good reads: