Keep talking. I’m glad to see a conversation between posters/readers.
I based my definitions mostly off of xUnit Testing Patterns (Gerard Meszaros). I might have taken some liberty though. I tend to not get too hung up on it.
The subtle difference between LightControllerSpy and FakeTimeService is that the LightControllerSpy does not provide any indirect outputs to its caller. Its job is strictly to spy on the the indirect outputs of the LightController.
The FakeTimeService is providing indirect outputs. I am probably not using Fake quite right. But that is OK in my opinion. It seemed to fit the best. So you might find people calling everything a Mock, even though the guys that invented the term use it in a more precise way. I use spy, when I’m just interested in checking if the right things are passed or the right number of calls are made. I use fake if its not really a spy, and not strictly a mock, though in the past I have used mock because of its broad acceptance. Dummy says, we really don’t care what happens.
Stub was the old term, and a stub usually was temporary in its pre-TDD role. With TDD the Test Doubles (Gerard’s most general term) do have long term value and are maintained through out the life of the software by whoever is responsible for the code/product. They help the maintainers as much or more than the original developers. They make automatic testing of unit possible, and unit testing is the only practical way to thoroughly test code.
Also keep in mind that the role of a test double could evolve, and then the name might need to be changed. Also, especially if function pointers are used, you might have several test doubles for the same thing for different purposes. There is another approach that did not make the book. That is to have a link time test double that you can install a function pointer into for different test double needs. (I need a blog post for this) This is handy when you want one link time stub, but different test scenarios have different needs from their test double. By using the function pointer, you can let each TEST_GROUP use exactly the stub they need.
One caution… it si real easy to prevent real work when arguing about the names. Names are important, but don’t make a life of being a lawyer about it at least in the case of test doubles classification. Pick the best fit and/or don’t sweat it.