Testing


A guide for testing effectively and some of the strategies we’re fond of here at Boltmade.

Who Tests

We all test. We test our own code, we test other peoples code, we test whatever needs to be tested so we can be certain what we’re delivering is high-quality stuff.

Testing Effectively

We test for a few different, but complementary goals:

  1. To know our code works.
  2. To know that when we change things, we don’t break other systems.
  3. To improve the design of our code.

Unit Testing

As defined by artofunittesting.com:

“A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behavior of that unit of work.”

Strategies we’ve found effective for unit testing:

  • We often find it helpful to write a few tests to define the API of our object first, so we can get a feel of how we want to use it.
  • We usually write our unit tests in a “behaviour” driven manner. The tooling you use will change how you can do this, but think in terms of contexts and blocks.
  • Ensure each individual test only tests one path/state/thing.
  • Use assertions about state for incoming messages.
  • Use stubs and spies to assert you sent outgoing messages.

Integration Testing

Wikipedia provides:

“Integration testing is the phase in software testing in which individual software modules are combined and tested as a group.”

Strategies we’ve found effective for integration testing:

  • Focus on high-risk, or high-complexity system integrations.
  • Always cover happy path, but cover the important unhappy paths too.

System Testing

Wikipedia provides:

“System testing of software or hardware is testing conducted on a complete, integrated system to evaluate the system’s compliance with its specified requirements. System testing falls within the scope of black box testing, and as such, should require no knowledge of the inner design of the code or logic.”

Strategies we’ve found effective for system testing:

  • These tests have a tendency to be brittle — and that’s okay.
  • Figure out the most important paths through the overall system, and test those.
  • A lot of interactions are often the same in every system test: encapsulate that into something you can reuse. (login, create user, fill out credit card info)

Other Considerations

Continuous Integration

We run almost every project with continuous integration, as part of our automated checks in our pull request process.

Test Coverage

The simple answer: whatever makes sense for your project. Think about what the constraints are, the goals, the requirements. You have to make a decision, and be able to defend it, so long as you can do that, you should be fine.

Auxiliary Benefits

  • Easy to test code is usually broken into small, focused components.
  • Side-effects are usually limited.
  • There are generally well thought out interfaces (especially if you wrote the tests first!).