Don't use injection for testing
The most exciting part when we can hear emitted states of our blocs and watch orchestrated calls of complete services to get things to work. A few days ago, we got a discussion about why using dependency injection in Flutter SDK is essential. Yeah, sure, it is the last letter in the SOLID acronym. But free talk born this blogpost.
Starting with what unit testing is. Is it a way to check the correctness of a code? Wrong behavior of code can be covered by passing tests and creating the illusion of controlling the flow. Even a hundred percent covered code can have a bug with passing tests.
Without mutation testing tool in Dart, we can't quickly test our tests (April 2021, the best candidate for adding support of mutation testing to it is likely to be Stryker since it already supports JS and TypeScript).
On the other hand, testability is not a fundamental goal when creating software. It's helpful for maintenance.
A quick look at typical architecture before jump to the test of different layers.
Infrastructure
We are testing data sources from what we want to ensure that those services expose what we expected. Test exception, which can occur on connecting to external or even internal services. Like DB, WebAPI, location, sensors, etc.
Domain
On this level, when we test, we can ask ourselves about classes. Should I split it into smaller entities? Some primitive obsession or method is doing too much stuff? When tests are difficult to write, we should answer this question first.
Application
The most exciting part when we can hear emitted states of our blocs and watch orchestrated calls of complete services to get things to work.
If the block does too much work, it cannot be easy to test too. So we can wrap action to 'use cases classes with contract what we expected then use services injected by a contractor or different use-cases. Then we can quickly test them with mocked services, and blocks can be divided into smaller classes not to harm the single responsibility principle.
Conclusion
With dependency injection, we can structure our code well. We can change communication of the classes by contract to use different implementations. Easy of testability are some things we got besides. DI helps us with the divide and win tactic when working with code.