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); // -> true

Python 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.

Still stuck?

The docs cover every SDK, and the free Solo plan is enough to reproduce most of these locally.