Testing 1
Managed and unmanaged dependency
There are two types of dependencies: managed and unmanaged. Managed are the ones controlled by application developers and consumed only by them, like a database used only by the application. Unmanaged are the dependencies which are out of control of devs, so stuff like SMTP server, queue or database used by multiple applications.
Mocking
Mocks should be used to verify calls to unmanaged dependencies only.
Interfaces with single implementation
There is only a single case when it’s allowed. To enable mocking of unmanaged dependencies. In any other case, just use a concrete class
Humble Object pattern
If a class has complex domain logic and many collaborators, we could use Humble Object
pattern: split class into two classess: a domain class having complex domain logic (having no collaborators) and a controller class, calling the domain class and collaborating with other classess. This way we end up with testable domain logic without use of mocks, and testable controller class via mocks
Database versioning
Always (almost) use migration - based approach. This way you’ve got your DB schema history (via version control) and you can easily resolve anny conflicts in DB changes.
Local database
Having multiple developers working on the same database is a no-go (assuming they’re not working on the same feature). Have an easily - creatable database and allow developers to create a database locally, it shortens the feedback loop drastically
Stub vs Mock
Stub is an object returning data, not verifying anything. Mock is an object intercepting calls to interface, in order to verify corectness of the call.
Mock vs Spy
Mock ckecks if the mocked interface got called and what parameters were passed to it. A spy is manually-created mock, which could hide the verifying logic in a nicely named functions.
Schools of testing
There are two main schools of testing. Classical
and London
. London relies more on mocking and verifying single class at a time, classical takes the approach of testing the whole unit at once (whatever the unit we’d call). Classical good, London bad.
Multiple Act & Assert stages in a single test
It’s illegal. There is only a single exception: when testing unmanaged dependency with some constraint, like daily api calls limit, slow sandbox environment etc.
Test pyramid
Can turn into test square with equal amount of integration and unit tests if project is small & simple.
Test coverage
It’s a really awful metric. I use it to determine the branch coverage.
What to test
Test only observable behavior. If logging is a part of business logic (user or manager will be checking the logs or metrics based on logs), then it’s worth testing. If logging is accessible only by devs, it’s not worth logging.
Domain events over services in domain
Instead of making calls to DB from domain layer in order to insert / update data, create list of domain events. This way you have not only tear the dependencies apart, but also make the domain logic easily testable by having a list of events containing the delta of all actions generated by domain logic.
Keep it positive
Testing is really hard. Just keep your head up high, it will be better.