A test can pass for the wrong reason. We had taken the WebSocket layer in EkoLite, our small real time backend, folded three almost identical socket classes into one wrapper, and watched the suite stay green. Then one test, the very one written to prove the work, turned out to be watching a copy of the behaviour rather than the behaviour itself. That is the symptom. This post is the part where we go looking for the word.
Because that is usually the order here. You do not start with the pattern and look for somewhere to apply it. You hit the wall first, then you need a name for the wall, and more often than not the name already exists. The vocabulary we reach for is James Shore's Testing Without Mocks, and not because we adopted it one afternoon. It is because the problems keep handing us the exact shapes he wrote down. The language comes from the need.
The question that cracked this one open was small and a little rude. What is the embedded stub of this module?
Two fakes that look the same
There are two ways to give your code something fake to run against, and from across the room they are identical. The difference between them is the entire job.
A Nullable, in Shore's sense, is production code with an off switch. You write one stub of the third party thing that talks to the outside world, the network, the file system, the socket library, and you make that stub behave so faithfully that your own code cannot tell it is there. Your code runs its real logic, start to finish, against something that simply does not reach the world. That stub is the Embedded Stub. It lives in the same file, it impersonates the library, and nothing above it is special cased.
A Stub Object is the other thing. It is a separate fake, and your code knows it is a fake. There is an if somewhere asking which one it is holding, a branch for the real path and a branch for the test path. It passes its tests. It also quietly testifies that the real path and the test path are two different pieces of code, which is exactly how a test can stay green while the thing it names is broken. We had met that ghost, a green test guarding a behaviour you could delete without waking it.
So here is the litmus, and it is the most useful question we know to ask of a Nullable. Can your production code tell whether it is holding the real thing or the fake? If it can, you do not have an off switch. You have a disguise, and the code can see straight through it.
What our code could see through
Ours could tell, in three places.
send and broadcast asked if (entry.stub), one branch pushing into the fake's array, the other calling the real socket. The connection handler reached into the socket and sniffed for a hidden hook that only the fake carried. And disconnect existed twice over, once in the close handler a real socket fires, once in a separate private method that only the fake ever called.
Every one of those is the code admitting that it knows. That is the signature of a Stub Object in a Nullable's clothes. Shore's instruction for going Nullable is one sentence and we had broken it without noticing: do not change your code, stub out the third party code instead. We had changed the code, all the way through, to make room for the fake.
So what is the embedded stub here
This is the part worth saying plainly, because it is the thing we were missing.
The wrapper touches exactly one piece of third party code that reaches the world: the ws library. So the embedded stub of this module is the in file stand in for ws, and because ws shows up at two heights, the stub is a pair. There is the thing that hands you connections, the server, which a null source stands in for. And there is the single socket you get for each connection, which a faithful null socket stands in for. Those two together are the off switch. Everything above them, the map of clients, the ids, send, broadcast, the close handler, the tracking, is your real code, and it should run the same whether the socket beneath it came from ws, from Fastify, or from the stub.
Said the other way, and this is the bit that stung: we did not have an embedded stub yet. We had a Stub Object in the costume. You will know it has become a real one the day you can delete every if (entry.stub), the hidden hook, and the duplicate disconnect, and the wrapper still compiles and still passes. That deletion is the goal. It is not a tidy up you do afterwards. It is the proof.
One thing to keep straight while we are naming things. The handle the test gets back when it simulates a connection, the object it uses to push a message in or read what was sent out, is not the embedded stub. That is the simulation seam, and it belongs hung off the fake, not bolted onto the boundary that every real socket also uses. The embedded stub is the quiet impostor underneath it. We had let the two jobs bleed together, which is why the boundary had a test only hook welded to its side.
What the rule was telling us
With the word in hand, the rest stopped being about taste and started being about the pattern. Behavior Simulation has a line that reads as if it were written for our bug: share as much code as possible with the code that handles real external events. Our simulated close ran one piece of code and our real close ran another. The fix is not clever. It is to make the fake's close fire the same handler the real socket fires, so there is one door in and the simulation walks through it like everyone else.
That is what we mean when we say our language comes from the pattern language. Nobody had to argue from authority. We had a shared set of words, Embedded Stub, Stub Object, Behavior Simulation, Overlapping Sociable Tests, and the words did the diagnosing. A review held in that vocabulary is a conversation about the code. A review held without it is a conversation about who has been here longest.
The tests that only exist once the fake is honest
Here is the quiet reward. The moment the embedded stub behaves like a real socket, a whole shelf of tests we could not write before becomes ordinary, and not a mock among them.
You can finally assert the thing that actually goes on the wire, because the fake captures what send really produced rather than pocketing the raw object before it was ever encoded. You can close a connection twice and prove the count drops once. You can send to a client that has already gone and prove it is a quiet no op and not a crash. You can prove the unsubscribe you handed back actually stops the callbacks. You can prove two connections get two different ids, and that a broadcast skips the client that just left. Every one of those is a narrow test against the off switch, fast and honest, with no live server anywhere in sight.
And one we keep coming back to, because it is the one people skip. The embedded stub is production code, so it has to earn its place. You write a small integration test that documents what the real ws socket does when it closes and when it sends, then a null test that fails the instant our stub drifts from that. Keep those two honest and the integration suite has one job left, to prove a real connection arrives and a real close fires. Everything else moves into the fast tests, where it belongs.
The move you can reproduce
You do not have to take our word that the disguise is gone. Open server/infrastructure/websocket.ts and go looking for the branch that asks which kind of socket it is holding. There is none. send and broadcast call socket.send with no if. The null socket's close fires the same onClose every real socket fires. The code cannot tell the switch is flipped, which is the definition we were after.
Then feel the reward it bought. Run npm run test and watch the socket wrapper's own tests pass with no server anywhere in sight: two connections get two ids, a broadcast skips the client that just left, a double close drops the count once, a send to a departed client is a quiet no op. Every one of those runs against the off switch, in milliseconds, because there is nothing left in the code that needs a real socket to be honest.
Where the words come from
We did not learn these names in a classroom and then go hunting for somewhere to use them. We built something, it went subtly wrong, we needed a word for the wrong, and the word was already in the pattern language waiting for us. That is the order we trust. The need first, the name second, the fix last.
A Nullable is production code with an off switch. The day your code can tell the switch is flipped, it was never a switch. It was a costume, and the test was only ever talking to the mask.


