Unit testing

As we described with our car analogy, a unit test is a test that deals with an isolated unit of code. This will usually be either a singular function or module that will make one or more simple assertions about the operation of the code.

Here are some examples of singular unit test scenarios:

  • You have a Button component that should contain the value Submit My Data and should have a class of btn_success. You can assert these characteristics via a simple unit test that checks the attributes of the produced DOM element.
  • You have a task-scheduling utility that will perform a given action at the requested time. You can assert that it does so by giving it a task to perform at a specific time and then checking for the successful execution of that task.
  • You have a REST API endpoint of /todo/list/item/{ID} that retrieves a specific item from a database. You can assert that the route works correctly by mocking the database abstraction (providing fake data) and then asserting that requesting the URL returns your data correctly.

There are several benefits of testing individually-isolated units of code:

  • Completeness: A given unit will typically have a small number of clearly defined requirements. As such, it's easy to ensure that you're testing the full gamut of a unit's functionality. All input variations can be tested quite easily. The very limits of each unit can also be tested, including the often complex minutiae of how something operates.
  • Reportability: When a given unit test fails, you can quite easily discern the exact nature and circumstance of the failure, meaning quicker debugging and fixing of the underlying problem. This is in contrast to integration tests, which, as we will discover, may have far more generic reporting that doesn't indicate the exact point of failure in the code.
  • Comprehension: Unit tests are a useful and self-contained form of documentation for given modules or functions. The narrowness and specificity of unit tests help us to fully understand how something works, easing maintainability. This is especially useful when there isn't up-to-date documentation elsewhere.
Completeness here is similar to the popular concept of test coverage. The crucial difference is that while coverage is about maximizing the amount of code within a code base that is tested, completeness is about maximizing the coverage of each individual unit, so that the entire input space of the unit is expressed. Test coverage, as a metric, only tells us whether things are tested, not whether they're well-tested. 

There are, however, challenges that come unit-testing as well:

  • Mocking correctly: Creating properly isolated unit tests sometimes means we have to constructs mocks or stubs of other units, as discussed in our former car analogy. It's sometimes challenging to create realistic mocks and to ensure that you're not introducing new areas of complexity and potential failures. 
  • Testing realistic inputs: Writing unit tests that provide a wide variety of realistic inputs is key although it can be challenging. It's quite easy to fall into a trap of writing tests that appear to give confidence but in fact don't test the kinds of situations that would arise when the code is in production.
  • Testing true units and not combinations: If not carefully constructed, unit tests can begin to bloat and become integration tests. Sometimes, a test can seem very simple on the surface but in fact depends on a series of integrations beneath the surface. To re-use our car analogy, an example of this would be if we were to attempt to make a simple unit test asserting the sound of the car horn without first isolating its circuitry. We'd unknowingly be creating an E2E test. 

The unit test, as the most granular type of test, is vital to any code base. It is perhaps easiest to think of it as a type of double-entry bookkeeping system. When you make a change, you must reflect that change via an assertion. This implementation-then-testing cycle is best done in proximityone after the otherperhaps via TDD, which will be discussed later. The unit test is your way of confirming to yourself that you truly wrote the code you intended to write. It provides a level of certainty and reliability that your team and stakeholders will be hugely grateful for.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.167.183