nus-cs3281 / 2022

http://nus-cs3281.github.io/2022/
2 stars 1 forks source link

Book: SE@Google Ch 12: Unit Testing #14

Open ryoarmanda opened 2 years ago

ryoarmanda commented 2 years ago

Book: Software Engineering at Google Chapter: 12 - Unit Testing

Summary:

Unit tests refer to tests of relatively narrow scope, like a single class or method. Due to it's prevalence compared to functional tests, maintainability of these tests is important for effective work. Maintainable tests, as opposed to brittle ones, are those that engineers write and are unchanging against the system under test; they are ensured that if the tests fail, those indicate real bugs.

To create maintainable tests, some good practices are:

  1. Test via Public APIs: Such tests are more realistic and less brittle because they form explicit contracts. If such a test breaks, it implies that an existing user of the system will also be broken.

  2. Test state, not interactions: Interaction tests check how a system arrived at its result, whereas the engineer should only care what the result is. Interaction details may change from refactoring, yet the result is not, therefore making tests on state to be less brittle.

  3. Make tests complete and concise: Only include information necessary for the test to produce the result, and no other irrelevant or distracting ones.

  4. Test behaviors, not methods: A single method often does a few different things internally. Instead of writing a test for the method, write a test for each behavior of the method, that is an assertion that the system makes when given certain inputs in a certain state.

    • Behaviors can be expressed as a "given"-"when"-"then" sequence, which is a good framework to structure behavior-driven tests
  5. Don't put logic in tests: In tests, choose straightforward code over clever logic, as logic creates another level of complexity to tests that we might fall into. Consider duplicating data when it makes the test more descriptive and meaningful.

  6. Write clear failure messages: A good failure message clearly distinguishes the expected from the actual state and gives more context about the result.

  7. DAMP, not DRY: While system code are generally DRY (Don't Repeat Yourself), opt for DAMP (Descriptive and Meaningful Phrases) in tests, as to make the tests understandable within its own and not to fully inspect test files to comprehend them.

    • Duplicate data, constants, interaction sequence, etc, reasonably
    • If test suite calls for shared values, use helper methods to create a default value that can be overridden by arguments.
    • If test suite calls for shared setups, override the initial values to the context of the test to minimize confusion.
    • Validation helpers should assert a single conceptual fact about their inputs, rather than a collection of them in one.