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 in the flag values your test needs, and that is the setup done.
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. The exact constructor name varies by language, so check the SDK reference for yours.
Why it is not the normal client
It performs no network calls and needs no initialization, so tests stay fast and run offline. It also 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 point is the one that bites if you roll your own. 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. Cover only the enabled path and you have tested half of what you shipped, usually not the half most of your users are running.
for (const enabled of [true, false]) { const client = FeatureflipClient.forTesting({ 'new-checkout': enabled }); // assert the behavior 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 behavior belongs in a staging environment against real configuration.
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.