这是indexloc提供的服务,不要输入任何密码
Skip to content

Testing

busterwood edited this page Dec 16, 2024 · 12 revisions

Unit Testing

Unit testing is a software development practice where individual components of a program, called "units," are tested in isolation to ensure they perform as intended. This practice should have been called "module testing" as a modules encapsulate functionality and exposes an interface while hiding the details of its internal implementation. This abstraction is crucial because it allows developers to test the behaviour of the module without being concerned with implementation details.

Good unit tests should focus on verifying the contract established by the module's interface rather than its internal workings. Bad unit tests are tightly coupled to the implementation details, such as internal methods or SQL, such that changes to the implementation can break the tests even if the module's behaviour remains consistent. This coupling increases maintenance effort and undermines the purpose of abstraction. To avoid this, tests should be designed to validate the module's interface and expected outcomes, ensuring that they remain robust and independent of internal design changes.

I have often seen good intentions lead to bad tests, e.g. 100% unit test coverage of implementation details, including the SQL generated and the parameters passed to methods being checked. What I would consider to be "Bad tests" also occurs because of the mis-understanding of what a "unit" is, so I very often see internal classes or functions being unit tested. Remember, bad unit testing costs time and money, both in up-front time as well as on-going maintenance costs, don't do it.

Include the database in the test

Back when unit testing became popular databases were much slower due to being "spinning disks of rust", so the advice was to "mock" the database otherwise the unit tests run to slowly to be useful. This is no longer true, you get a fresh copy of a Postgres database in a little as 150 ms by using database templates, setting the Write Ahead Log to minimal and turning off fsync.

End to end tests

No matter how many unit tests there are, the concern of any software is does it work end-to-end, i.e. when the user does this, the outcome is that. Here the focus will be business processes that involve multiple user interactions. Focus first on success (happy paths), then on key failure paths.

End-to-end tools

There is good advice on what makes a good or bad test from the Concordion FAQ page.

Mocks

I see Mocks massively overused. Mocks can be useful, but typically should only be used for Mocking major external dependencies, e.g. a payment API, or a very expensive API call. If you are not mocking something like that, then don't use a mock, test the module including the dependency.

Clone this wiki locally