I am new to adopting a completely TDD approach using DI so that I can mock every dependency. One of the pain points that I identified so far is the fact that whenever I do work in my constructor every test has to prepare for that sequence (expect the corresponding mock calls). An example for such a sequence might be creating sending a message or checking if a folder exists, etc.
Are there any best practices how to handle such situations. Right I consider the two options:
- No work in the constructor (cumbersome since I need to manually need to make sure the object's invariants are satisifed)
- Test the boot sequence individually and only work with intialized objects in the test afterwards
I could not really find insights on google how those problems are handled in general. Am I following a poor design principle?
Edit, Example added:
struct CachedObservable {
INJECT(CachedObserable(
std::shared_ptr<IO> io,
std::shared_ptr<Observable> base
))
{
load_and_emit_cached_file_from_hdd_if_available(io);
base->subscribe([this](auto& x) {
save_value_in_file(cached_filepath);
emit(x);
});
}
void load_and_emit_cached_file_from_hdd_if_available(
std::shared_ptr<IO> io
)
{
if (io->file_exists(cached_filepath))
emit(io->load(cached_filepath));
}
...
};
The example is an abstraction but captures the real use-case. I use fruit & rxcpp to have a replay subject that does two things:
- On construction load a cached value from a file on the hdd and emit the content
- Forward all values emitted from the injected observable and cache the latest object
I use mocks for both io and observable to completely isolate the behavior of the class