The double that drifted
All labsTwo implementations of the same interface: a real one and an in-memory fake used in tests. A double is a claim about how the real thing behaves, and nothing checks that claim — unless you write a contract test, which is one suite run against both. Both are exported here, so you can do exactly that.
goalWrite one suite that passes against both implementations — and would fail if either changed.
The module
export function createStore() {
const rows = new Map();
return {
put(key, value) {
if (typeof key !== "string" || key.length === 0) {
throw new Error("key must be a non-empty string");
}
rows.set(key, value);
return value;
},
get(key) {
return rows.has(key) ? rows.get(key) : null;
},
remove(key) {
return rows.delete(key);
},
keys() {
return [...rows.keys()].sort();
},
};
}
export function createFakeStore() {
const rows = {};
return {
put(key, value) {
if (typeof key !== "string" || key.length === 0) {
throw new Error("key must be a non-empty string");
}
rows[key] = value;
return value;
},
get(key) {
return key in rows ? rows[key] : null;
},
remove(key) {
if (!(key in rows)) {
return false;
}
delete rows[key];
return true;
},
keys() {
return Object.keys(rows).sort();
},
};
}
Your tests
Mutants
Run the suite to see the board.