What is "fake it till you make it" in TDD, and when do you stop faking?
answer
- Two uncertainties, separated into two moves
- Smallest possible green, on purpose
- The literal appears twice on purpose
- Remove duplication by generalising the code
- Constant, then expression, then parameters
basics
~20 sFake it till you make it means passing a new failing test with the smallest code possible, often a hardcoded constant, then generalising once further tests demand it. The fake proves the test really discriminates before any design work begins.
solid answer
~50 sWhen a test first fails, you have two things to establish: that the test genuinely detects the behaviour, and that the behaviour is correct. Faking separates them. You return the literal value the test expects, watch it go green, and now you know the test is wired to the code and fails for the right reason. The hardcoded value is deliberate, visible duplication between the test and the implementation, and removing that duplication is what drives the real algorithm out. You stop faking as soon as a second case makes the constant untenable, or as soon as the general form becomes obvious to you — at which point you write it directly instead of faking. What you must never do is leave a fake in place and move on to the next feature; the fake is a step, not a destination.
code
pseudocode · 15 linestest "cancelled on day 11 of a 30 day period charges 1943 cents":
charge = prorate(periodDays = 30, usedDays = 11, fullPriceCents = 5300)
assert charge == 1943
# green by faking
function prorate(periodDays, usedDays, fullPriceCents):
return 1943
# still green, duplication now expressed as arithmetic
function prorate(periodDays, usedDays, fullPriceCents):
return round(5300 * 11 / 30)
# still green, fake fully removed
function prorate(periodDays, usedDays, fullPriceCents):
return round(fullPriceCents * usedDays / periodDays)go deeper
Be ready to state plainly that returning a hardcoded value to pass a new test is a legitimate first move, and that you remove it before writing the next test. Say what the green run proves: the test is wired up and really detects the behaviour.
Explain the mechanics of removing the fake — literal, then expression over literals, then expression over the parameters — and why the duplicated value between test and code is the signal that tells you what to generalise.
Show that step size is a dial you adjust from evidence. Say what makes you shrink steps on real work: an unexpected red, unfamiliar code, a defect where you were confident. Also name the abandoned-fake failure and how review catches it.
Own the framing that faking is uncertainty management, not ritual. Be ready to say when a team's mechanical faking is costing cycles, and how you would coach step size rather than mandate one strategy for everyone.
## The idea "Fake it till you make it" is one of the named strategies for getting from a failing test to a passing one. Instead of implementing the behaviour the test describes, you write the least code that could possibly make the assertion true — typically returning the exact literal the test expects — and let the suite go green. Then you remove the fake, either because a further test makes the constant impossible or because the real implementation has become obvious. It looks like cheating, and candidates often describe it apologetically. It is not cheating, because the fake is never allowed to survive. It is a way of splitting one uncertain move into two certain ones. ## What faking actually buys you **It proves the test discriminates.** A test that has never passed and never failed for a reason you understand is not yet a test. Faking gives you a controlled green: you know the runner picks the case up, the call compiles, the assertion compares the right things, and nothing in the setup is silently swallowing the result. If a hardcoded return does *not* turn the case green, the problem is in the test or the wiring, and you have found that before writing any logic. **It moves the design problem out of the red bar.** While the suite is red you are under pressure; every extra minute is a minute you cannot safely refactor. Faking gets you to green in seconds and lets you do the thinking with a net underneath. **It makes the missing generality visible as duplication.** This is the subtle part. After faking, the same value appears twice: once in the test as the expectation, once in the code as the return. That duplication is the exact distance between what you have and what you need. The rule of thumb is that you remove duplication between test and code by generalising the code — replacing the constant with an expression over the inputs — not by weakening the test. ## A worked increment A subscription renewal job must compute the prorated charge when a plan is cancelled part-way through a billing period. ```pseudocode # Step 1: the failing test test "cancelled on day 11 of a 30 day period charges 1943 cents": charge = prorate(periodDays = 30, usedDays = 11, fullPriceCents = 5300) assert charge == 1943 # Step 2: fake it -- smallest possible green function prorate(periodDays, usedDays, fullPriceCents): return 1943 # Step 3: the constant is duplicated in test and code; # start replacing it with the inputs function prorate(periodDays, usedDays, fullPriceCents): return round(5300 * 11 / 30) # Step 4: the remaining literals are the parameters function prorate(periodDays, usedDays, fullPriceCents): return round(fullPriceCents * usedDays / periodDays) ``` Steps 3 and 4 are the "make it" half. Notice you can take them gradually: literal, then expression over literals, then expression over parameters. Each of those is a separate green run. That gradualness is the whole point — you are never more than one small edit away from a state you know works. ## When to fake and when not to Faking is not the only way to go green, and reaching for it every time is as mechanical as never reaching for it. The three commonly named strategies are: - **Obvious implementation** — you know the code, it is a line or two, you type it and run. Use this when you are confident. If it goes red twice in a row, drop back to smaller steps. - **Fake it** — you are not sure of the shape yet, or you do not trust the test wiring. Use this at the start of a new component, in unfamiliar code, or after a surprise. - **Triangulation** — you write a second, differing case specifically to force the general form out. Use this when the general form is not obvious even after faking. Step size is a dial, not a setting. Experienced practitioners take large steps when the ground is familiar and shrink them the moment something surprises them: a test that fails unexpectedly, an unfamiliar interface, a bug found in code they thought they understood. ## How it goes wrong The common failure is the abandoned fake — a hardcoded return that stays because no test ever forced it out, so the feature appears to work in the suite and does nothing in production. The discipline is that a fake exists only inside the current increment; if you are about to write the *next* test for a different behaviour while a fake is still standing, you have skipped a step. The other failure is faking something that was obvious anyway, which wastes cycles and makes the practice feel like ritual rather than a tool for managing uncertainty. Also note what a fake is *not*: it is not a stand-in for a collaborator, and it is not a placeholder feature flag. It is a temporary literal in the code under test, removed within the same increment.
- If faking gets you to green, what stops the fake from shipping?Nothing automatic does, which is why the discipline puts removal inside the same increment: you generalise the constant before writing a test for any other behaviour. Practically, the duplicated literal between test and code is the reminder, and a second case that exercises different inputs makes the fake fail outright. Reviewers should treat a hardcoded return whose value matches a test expectation as an unfinished increment, not as an implementation.
- When would you skip faking and write the real implementation immediately?When the implementation is obvious to you — a line or two you are confident about — and the test wiring is already proven, because the component has passing cases. Faking buys certainty you already have there, so it only costs cycles. The signal to drop back to faking is surprise: an unexpected red, an interface you have not called before, or a defect found in code you believed you understood.
- How is faking a return different from substituting a stand-in for a collaborator?A fake return is a temporary literal in the production code under test, put there by you and removed within the same increment. A stand-in replaces a collaborator the code calls, lives in the test, and is a permanent part of that test's arrangement. They are unrelated techniques that share a word: one is a step in growing an implementation, the other is a way of isolating one.
It is like sketching a straight line before drawing the curve: the sketch is not the drawing, but it proves your pencil marks the paper and shows you exactly how far the real shape has to move.
saying these in an interview costs you the question
- Calls faking cheating and refuses to ever do it
- Leaves the hardcoded value in and moves to the next feature
- Thinks faking means substituting a collaborator
- Weakens the test instead of generalising the code
- Fakes every increment mechanically, even obvious ones
- Cannot say what the fake proves about the test