3 Testing
Lex Berezhny edited this page 2018-08-21 23:06:28 -04:00

"Write a manageable amount of thoughtful unit tests to aid in future refactoring but prefer integration tests to prove your code actually works." - Zen of LBRY Development

When deciding what tests to write, at what scope to write them and how many to write you are performing a balancing act between developer productivity, accruing technical debt and quality of the end product.

Several testing types are covered below with various do's and dont's to help you stay balanced.

Unit Tests

  • Limit unit tests to testing an isolated single unit of code: function, class and/or module.
  • Unit tests should not break when unrelated functions, classes or modules are changed.
  • Use test driven development when it helps your flow.
  • Fast running unit tests help you to stay focused and confident in what you're doing.
  • Ensure that edge cases are covered by the unit tests when it would otherwise be difficult, prohibitively time consuming or require significantly more lines of code (higher technical debt) to test via integration tests.
  • Use mocks to avoid turning your isolated tests into integration tests that depend on other modules.
  • Recognize that unit tests don't prove that your code actually does what it's intended to do, they only prove that the code is internally consistent with itself and with the tests. Integration and end-to-end testing is more apt at validating that the code meets its objective by taking into account the entire system as a whole.
  • Technical debt from too many tests is most apparent when refactoring APIs or making substantial changes to the code - you end up making every change several times, once in the implementation and a bunch of times in the tests. Keep your future self in the back of your mind when writing tests, don't make it unnecessarily hard to refactor. The more times you go through the cycle of writing tests and having to refactor them the more concise your test writing will get over time.
  • Feeling uneasy that you are breaking stuff during refactoring is an indication that there isn't enough test coverage.
  • Strive for 100% test coverage if it's easy and at least 90% if it's hard.

Integration Tests

  • An integration test covers two or more units of code and should avaid mocks as much as possible.
  • Integration tests are primarily for proving your code does what it was designed to do and that it plays well with the rest of the code in the application.
  • Each public facing interaction point (API, protocol, etc) should have an adequate battery of integration tests.
  • Every use case or feature of the application should have integration tests showing how to exercise the feature or perform the use case and the expected results of those operations.
  • Well written integration tests can act as a form of documentation and the authoritative specification of a feature with built-in self-validation.