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.

// Mock
var serviceBusMock = new Mock<IServiceBus>();
var sut = new Xx(serviceBusmock);
// ..
serviceBusMock.Verify(s => s.SendMessage("ItemsProcessed", 17), Times.Once());

// ---

// Spy
var serviceBusSpy = new ServiceBusSpy();
var sut = new Xx(serviceBusSpy);
// ..
serviceBusSpy
    .SentItemsProcessedMessage(17)
    .ExactlyOnce();

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.