I like to use real things as much as posible but I find lot of people using too much mocks sometime. Can you provide some advise on how to decide mocks vs real services/dependency?
Could not find any good blog on the this specific topic.
If A depends on B depends on C, then:<p>* C should have a unit test proving its capabilities.<p>* B is allowed to have a unit test that depends on C (because C's unit tests prove its correctness).<p>* A is allowed to have a unit test that depends on B (similar to the B/C case).<p>---------<p>It seems like mocking was a way to "cut" the dependency between A and C. In particular, you usually get huge "dependency chains" between your code base. A depends on B, depending on C, depending on D... depnds on E, F, G, H, I... etc. etc. Pulling in all of this code for a unit test seems backwards. IMO, the solution isn't to use mocking, but to refactor your code to reduce the dependencies.<p>But if the code is outside of your control (ie: owned by another team, or even a 3rd party), maybe mocking is the best option.<p>"Flattening" your code dependencies, reducing the "height" of your layers will simplify your code logic and software engineering. But its not always an option in reality.<p>------<p>If you have a circular dependency: A depends on B and B depends on A, then:<p>1. Find a way to break the circular dependence. Invent a new class C: Maybe A depends on C, B depends on C, and C represents the shared interface between the two. Once broken up in this manner, A depends on C (and A unit tests depend on C), then B depends on C (and B unit tests depend on C), and finally you write unit tests for C itself. No mocking needed.<p>2. If #1 cannot happen, Both A and B must be unit tested together as a singular component. Trying to split it up using mocking is a fool's errand.
Well, I had to use mocks when interacting with a device through Bluetooth Low Energy. It's a hardware device that can't be in a CI/CD pipeline.<p>I pushed the hardware part into a class, injected it as a dependency to client code so I could materialize the BLE connection whenever I wanted.<p>The binary encoding/decoding wasn't tied to the class and was handled by a codec I wrote to decouple packet handling from the device. You only had to feed it a YAML file I wrote to model the device communication protocole. I read the manufacturer's specs and came up with a schema for rx/tx padding, etc.<p>When we changed devices, we just had to give another YAML file to the codec and the code worked.<p>All this to say that it was really hard to test before code refactoring and loosening the dependency on the actual device.<p>Once we had a nice interface, you could write a MockBLEDevice class even by inheriting from the real class, just changing the actual BLE connection to return something else and keeping everything else the same.
There's no best way and time is a limited resource. Weigh up the time it's going to take and the pros/cons for your specific project. If you've done this and think mocking is going to take up too much time for not enough benefit then you've made a good tradeoff.
Test what you are testing. Are you testing a method or function? Mock its inputs. If your test of a function fails because an API or a database is not available, that's approaching an integration test. If there's a question of whether there are too many mocks being used, the dev may not have thought out a testing strategy well enough. Be certain of what you're testing.<p>That's what I usually go by.