Skip to content

Archive

Testing

55 articles
Software Engineering 03 Sep 2026 6 min read

Refactoring Legacy Code with Characterization Tests

Legacy code is difficult to change when its important behaviour is poorly understood and existing tests do not provide enough confidence. The risk is not only that a refactoring introduces a bug. The deeper problem is that developers may not know which behaviours are intentional, accidental, or relied on by other parts of the system. Characterization tests help reduce that uncertainty. Instead of beginning with a specification of what the code should do, they capture what the code does today. That behavioural baseline can make structural improvement safer while the team learns the system.

Software Engineering 03 Sep 2026 7 min read

Mutation Testing for Stronger Test Suites

A test suite can execute every important line of code and still miss serious defects. Coverage tells you which code ran, but it does not tell you whether the tests would notice if that code behaved incorrectly. Mutation testing examines that gap. It makes small, systematic changes to production code and runs the tests against each changed version. If the tests fail, the mutation is killed. If they still pass, the mutation survives and points to a place where the suite may not distinguish correct behaviour from incorrect behaviour.

Software Engineering 03 Sep 2026 8 min read

Creating Seams for Safer Code Changes

Some code is difficult to change for reasons that have little to do with the change itself. A function may read the clock directly, create its own network client, access a global configuration object, or write to a file in the middle of business logic. The requested change may be small, but verifying it safely becomes difficult because the code is tightly connected to things that are slow, unpredictable, or hard to reproduce.

Software Engineering 03 Sep 2026 6 min read

Choosing Test Doubles Without Hiding Design Problems

Test doubles are useful when a test needs control over a dependency that would otherwise be slow, unpredictable, expensive, or difficult to observe. They can also make a test suite fragile when every internal interaction is replaced and asserted. The goal is not to avoid test doubles. It is to use the least powerful double that gives the test the control or evidence it needs. Start with the reason for replacing a dependency Before introducing a double, identify what makes the real dependency unsuitable for this test.

Software Engineering 03 Sep 2026 8 min read

Characterization Tests for Safe Legacy Changes

Changing old code is difficult when nobody can say with confidence which behaviours are intentional and which are accidents. Documentation may be incomplete, the original authors may be unavailable, and existing tests may cover only a small part of the system. In that situation, writing tests for the design you wish the code had can be risky. Before improving the design, you first need evidence about what the software actually does today.

Go 01 Sep 2026 8 min read

Testing Go HTTP Handlers with httptest

HTTP handlers are one of the easiest parts of a Go service to test well. You usually do not need to bind a real network port, start the entire application, or depend on an external test framework. Go’s standard library provides net/http/httptest, which can construct HTTP requests, capture handler responses, and even start temporary HTTP servers when a real client-server round trip matters. This guide builds a small JSON endpoint and tests it at several useful levels.

Software Engineering 01 Sep 2026 4 min read

Contract Tests for Reliable Service Boundaries

Distributed systems fail in an awkward place: each service can pass its own tests while the interaction between two services is incompatible. A provider may rename a JSON field, tighten validation, change an enum, or stop returning a value that a consumer quietly depends on. Contract tests make those cross-service assumptions executable. What a contract is A contract describes an observable interaction between a consumer and a provider. For an HTTP API, it might specify: