Testing Approaches
An approach is how you design and drive tests, independent of what you test. Two axes matter most: how much of the implementation you can see, and when you write the test relative to the code.
By knowledge of the implementation
Section titled “By knowledge of the implementation”| Approach | You see | Typical use | Weakness |
|---|---|---|---|
| Black-box | Only inputs and outputs | Acceptance, E2E, API, functional tests | Misses untested internal branches |
| White-box | The source code and structure | Unit tests, coverage-, mutation-driven tests | Can over-fit to implementation |
| Grey-box | Some internal state/logs | Integration tests, security testing | Requires discipline to stay useful |
Black-box
Section titled “Black-box”You treat the system as an opaque box: given this input, expect that output. Tests survive refactors because they never touch internals.
import { test, expect } from 'vitest';
// No knowledge of how `add` is implemented.test('add sums two numbers', () => { expect(add(2, 3)).toBe(5);});def test_add_sums_two_numbers(): assert add(2, 3) == 5func TestAdd(t *testing.T) { if Add(2, 3) != 5 { t.Fatalf("want 5, got %d", Add(2, 3)) }}@Testvoid addSumsTwoNumbers() { assertEquals(5, calc.add(2, 3));}[Fact]public void Add_SumsTwoNumbers() { Assert.Equal(5, Calc.Add(2, 3));}White-box
Section titled “White-box”You inspect structure. Coverage tools and mutation testing live here; so do tests that deliberately exercise a specific branch.
// White-box: we assert on the internal branch we just wrote.if (items.length === 0) return { total: 0, empty: true };Grey-box
Section titled “Grey-box”Partially informed by internals — e.g. an integration test that seeds a database directly, or a security test that reads the app’s logs.
By when you write the test
Section titled “By when you write the test”| Practice | Meaning | Cycle |
|---|---|---|
| TDD — Test-Driven Development | Write a failing test, make it pass, refactor | Red → Green → Refactor |
| BDD — Behaviour-Driven Development | Tests written as plain-language scenarios (Given/When/Then) |
Feature → Scenarios → Steps |
| ATDD — Acceptance-Test-Driven Development | Acceptance criteria written as tests before coding | Criteria → Test → Code |
| Test-after | Tests written after the code | Risky: the code “defines” correctness |
1. RED — write a test that fails for the right reason2. GREEN — write the minimum code to pass3. REFACTOR — clean up, keep the test greenBDD with Gherkin and Robot Framework
Section titled “BDD with Gherkin and Robot Framework”BDD scenarios are written in Gherkin so non-programmers can read them:
Feature: Login Scenario: Reject a wrong password Given a registered user "ada" with password "s3cret" When the user signs in with password "wrong" Then the user sees "Invalid credentials"Robot Framework is a keyword-driven, Python-based automation framework with its own tabular, plain-language syntax — widely used for BDD-style acceptance and RPA. It needs no programming to write the high-level test:
*** Test Cases ***Reject A Wrong Password Given a registered user "ada" with password "s3cret" When the user signs in with password "wrong" Then the user sees "Invalid credentials"Its ecosystem (SeleniumLibrary, RequestsLibrary, AppiumLibrary) makes it a strong choice for acceptance testing across web, API and mobile from one syntax.
Manual vs automated
Section titled “Manual vs automated”| Manual | Automated | |
|---|---|---|
| Best for | Exploratory, usability, one-off checks | Regression, repeated, high-volume |
| Cost profile | Cheap to start, expensive to repeat | Expensive to start, cheap to repeat |
| Evidence | Human judgement, screenshots | Deterministic pass/fail, artifacts |
Most healthy teams do both: automate the regression suite, and reserve humans for exploratory and usability work where judgement is the point.
Self-assessment quiz
Section titled “Self-assessment quiz”Self-assessment quiz
Pick one answer per question, then press Check answers.