Lots of people in the comments here stuck on the boring semantic definition debate of mocks vs stubs vs nulls vs whatever.<p>This is not really by what the article is about IMHO. It’s a great overview of how to grow and organize your application with some opinionated patterns that give some favorable properties to your system. The nullable stuff just helps achieve those properties. If you want to use a mocking library to write nullables, and call them mocks, fine. Not important.
Hi everyone, author here. This article tends to raise a lot of questions. I'm happy to answer them.<p>(The most common question: isn't it the same as a mock? The answer is no, mocks are used for isolated, interaction-based testing, and this is for sociable, state-based testing. These are polar opposite approaches to testing with distinct tradeoffs. If you're not familiar with those terms, they're defined in the article in the "Foundational Patterns" section.)
This seems close to what I do, except I dependency inject the alternate implementations rather than modifying production ones to do the job, which seems weird. Plus I may want more than one implementation.<p>At least at the scale of code I've been working with, it has been excellent. People keep threatening me with dire promises of how this or that testing practice will result in fragile, highly-coupled tests, and all I can say in response is that in 10+ years of continuously writing tests you'd think it would have happened to me by now. Instead I tend to make very reasonable changes to my tests as I go, and the only times I've ever ended up rewriting them top to bottom is when the underlying code under test changed so much that it was inevitable anyhow.<p>I tend to have a test module that sets up an entire test environment with all the stub implementations, which works fairly well in that middle ground between full integration and unit tests.
Reposts are fine after a year or so (<a href="https://news.ycombinator.com/newsfaq.html" rel="nofollow">https://news.ycombinator.com/newsfaq.html</a>) but this had a major thread just a month ago, so it counts as a dupe:<p><i>Testing Without Mocks: A Pattern Language</i> - <a href="https://news.ycombinator.com/item?id=34293631" rel="nofollow">https://news.ycombinator.com/item?id=34293631</a> - Jan 2023 (76 comments)<p>Previously:<p><i>Testing Without Mocks: A Pattern Language (2018)</i> - <a href="https://news.ycombinator.com/item?id=30565918" rel="nofollow">https://news.ycombinator.com/item?id=30565918</a> - March 2022 (28 comments)<p><i>Testing Without Mocks: A Pattern Language</i> - <a href="https://news.ycombinator.com/item?id=16943876" rel="nofollow">https://news.ycombinator.com/item?id=16943876</a> - April 2018 (12 comments)
My introduction to mocking was through C++ and googlemock, where you have to dependency inject the mock object to do any mocking. This always made sense to me, and could often make APIs nicer and more generic with this approach. The API for dependency injection just ends up an other public interface that you need to test, and one natural way to test it is with mock objects.<p>Then I learned about pytest, magicmock, and that the norm for other testing frameworks in other (mostly dynamic) languages is that you can replace whatever member or free function with a mock without this being part of the public interface of the original class or function. This feels insane to me, as this just tests implementation details.<p>Is there terminology to distinguish between these two kinds of mocking?
If you make all your code as pure function, then testing is easy.<p>First thing to do: Stop using class. Ask yourself first: Should i use a class here and there ?<p>Wait, i miss something here: Writing pure functions is hard ?
Obviously he's keeping the interesting bit about how this works for the actual course, but I already only mock bits right on the edge, e.g. the point where the system would connect to the outside world, and that seems to work.<p>What I'd really like, is some way of acknowledging redundancy - lots of tests ultimately go through the same code underneath, it would be good if that could be tested only once, and then the data replayed from those points <i>but</i> done in such a way that everything is still nice and readable.
I get that in other software stacks you might want to avoid mocks and stubs due to friction, but in JavaScript what's the big deal? Mocks are easy– just do it.
Seems like a lot of work just to avoid mocks. Don’t know if this is language specific but I find it’s really easy to create mocks and/or in-memory substitutions in .NET using something like Moq.
A "fake" (as opposed to a mock) is a pretty well understood concept.<p>Is there a difference between a fake and a "nullable"? As far as I can tell this is a pattern for merging your fakes and reals which seems cumbersome and error prone
> The factory should create a “Nulled” instance that disables all external communication, but behaves normally in every other respect....<p>>...For example, calling LoginClient.createNull().getUserInfo(...) should return a default response without actually talking to the third-party login service.<p>So... a mock.