Specification is security
Most testing checks the system does what was built. We check it does what was intended. The difference between those two is where the expensive problems hide.
The most dangerous problems in software aren't code bugs. They're things nobody thought to define.
The gap problem
Every system has gaps between what was specified and what was built. A payment rule that seems robust until you ask what happens at midnight. An API endpoint that checks permissions on one path but not another. A rate limit that applies to individual requests but not batched ones.
These gaps are where bugs live. They're also where attackers live. Not in the code that was written, but in the behaviour that was never specified. The discipline of finding what's missing is the same whether you're preventing defects or preventing breaches.
Testclub was founded in 2012, on twenty-five years of this work. We started in functional testing and specification and branched into security because the skill is identical. Understand how a system is supposed to work, then think clearly about how it doesn't.
“Everything is vague to a degree you do not realise till you have tried to make it precise.”
Bertrand Russell
How we think about testing
Testing is not verification after the fact. It's a way of thinking about systems before, during, and after they're built. The most valuable testing happens at the specification stage, when asking the right question can prevent a class of defects entirely.
We use structured examples to drive out ambiguity. What should happen when a user submits an empty form? What if they submit it twice in the same second? What if the session expires between steps two and three of a payment flow? These aren't edge cases. They're the cases nobody wrote down.
This approach applies equally to functional correctness and to security.
An unspecified behaviour is an untested behaviour, and an untested behaviour is an attack surface.
This is not just a testing technique. It's a collaborative process that prevents defects before code is written. When a team specifies a feature precisely enough to automate against, ambiguity gets driven out early. The specification and the test become two sides of the same thing.
Three sectors, one discipline
Functional. Most testing happens after the code is written, checking that it does what it does. This is different. Specification by example happens before a line is written: given, when, then, turning what should happen into a test a machine can run before there's anything to test against. Twenty-five years later, we still do this work for teams who want it. It's also where the other two sectors below learned their discipline.
Web / API security. Most vulnerabilities are mistakes in code someone else wrote: a dependency, a library, a known pattern a scanner can match. A business logic flaw is different. The code does exactly what your team built it to do. The problem is what it lets someone do with that. A discount applied twice, a step skipped, an order cancelled after it's shipped: these aren't bugs in the usual sense. They're decisions nobody checked from the attacker's side.
LLM security and evals. A traditional check is binary: it's there, or it isn't. AI systems aren't. The same question can get a different answer twice, and a model that holds against an attack this month can fail to a new one next month. Security testing treats the system as an adversary would, looking for the conditions where it stops behaving as intended. Evaluation asks the quieter version of the same question: not whether it can be broken, but whether it's actually right, run after run.
Where the functional discipline still runs
Load & performance
Identifying bottlenecks and breaking points under realistic conditions. Capacity planning and performance baselines.
End-to-end browser testing
Automated acceptance tests across browsers, delivered into your repo and CI pipeline.
Specification by example
Turning business rules into executable specifications that serve as both documentation and regression suite.