Most .NET test projects rely on NSubstitute and Castle.DynamicProxy. That foundation is cracking: NativeAOT breaks it, trimming strips it, cold-start costs accumulate. TUnit.Mocks takes a different route: a source generator emits typed mocks at compile time, IService.Mock() (or Mock.Of<T>()) is the entry point, runtime reflection is gone.
The first four parts of this series treated legacy as something between me and myself: Past Self leaving code for Future Self, with an AI in the middle. That framing is incomplete. Code outlives employment, not just memory. The companies I worked for have forgotten most of what I did there. The repositories haven’t. This is the fifth part of the Code as Legacy series, about the legacy you leave when you’re not around to defend it.
Part three ended with me promising to stop adding to Past Self’s pile. I was already wrong. I’m not the only author anymore: Copilot and Claude finish methods before I’ve finished thinking, shipping code under my name with my git config as the committer. This is part four of the Code as Legacy series, about what changes when the author is partly a machine.
AI coding agents make you faster. They also make your bugs faster: they generate plausible-looking code, you review quickly, the tests pass, and production breaks two weeks later. I keep falling into this pattern myself, always on the happy path, telling myself the edge cases come later. They don’t. Here’s the pattern, why most test frameworks make it worse, and how TUnit fights it.
I’ve spent two articles in this series describing Past Self and the damage he left behind. What I haven’t said yet is the uncomfortable part: I am Past Self, right now, making the same promises he made. // TODO: fix this properly. We’ll clean that up after the release.I’ll write the tests when there’s time. This is the third part of the Code as Legacy series, and I’m deciding to stop.