How do I test code that uses feature flags?
Last updated:
Use the test client each SDK provides. You construct it with a map of flag keys to values and it evaluates against that map, with no network calls and no initialization step. It is not registered in the normal client cache, so every call returns an independent instance and tests cannot leak state into each other.
Mocking the SDK yourself works right up until the surface changes underneath you. Every Featureflip SDK ships a purpose-built test client instead, so you assert on your own branching rather than on a stub you maintain.
The shape
Pass the flag values the test needs. That is the whole setup.
import { FeatureflipClient } from '@featureflip/node';
const client = FeatureflipClient.forTesting({ 'new-checkout': true, 'checkout-copy': 'variant-b',});
client.boolVariation('new-checkout', false); // -> truePython and Java are the same idea:
client = FeatureflipClient.for_testing({ "new-checkout": True,})FeatureflipClient client = FeatureflipClient.forTesting(Map.of( "new-checkout", true));Go exposes a package-level ForTesting() that behaves the same way.
Why it is not the normal client
Two properties matter here.
It performs no network calls and needs no initialization, so tests stay fast and run offline. And it sits outside the client cache the SDKs use to guarantee one shared instance per process, which means each call hands back an independent client. Two tests configuring the same key to different values cannot interfere.
That second property is the one that bites if you roll your own, because the production client is deliberately shared and a hand-built singleton mock will happily leak the last test’s flag values into the next.
Test both sides
The point of a flag is that two paths exist. A suite that only covers the enabled path is testing half the code you shipped, and the half that runs for most users is usually the other one.
for (const enabled of [true, false]) { const client = FeatureflipClient.forTesting({ 'new-checkout': enabled }); // assert the behaviour you expect on each side}Keep the default you pass at the call site in mind too. It is what runs during an outage, so it deserves a test of its own rather than being treated as unreachable.
What this does not cover
Targeting rules and rollout percentages live in the flag configuration, not in your code. The test client returns the value you gave it, so it verifies your branching and says nothing about whether a rule is correct. Rule behaviour belongs in a staging environment against real configuration.
Per-SDK details are in the SDK reference.
Related questions
Do I need a user ID to evaluate a feature flag?
Only for percentage rollouts. Without a stable identifier a server SDK serves the control variation, and the hosted endpoint spreads traffic with no stickiness.
Why is my feature flag returning the wrong type?
SDKs do not coerce types. Asking for a boolean from a string flag returns the default you passed rather than converting, so code and dashboard disagree.
Why do two users get different variations?
That is what a percentage rollout does. Bucketing hashes the user ID with the flag key, so the split is per user and per flag, and never lines up across flags.
Still stuck?
The docs cover every SDK, and the free Solo plan is enough to reproduce most of these locally.