On Sunday, 7 December 2014 at 13:47:09 UTC, Dicebot wrote:
However I was not speaking about plain procedural/imperative
paradigm as better alternative but functional and generic ones.
First one helps with eliminating state in general. Second one
allows to use the very same mocks in much more light-weight way
because no runtime binding is necessary - no dependency
injection stuff and unnecessary interfaces, just using stub
policy is enough.
To give some examples from personal experience of what frustrates
me in typical OOP testing approach:
Imagine we have a simple cache class that internally communicates
with external dht:
class Cache
{
private DhtClient client;
this(string addr) { this.client = new DhtClient(addr); }
}
Now we want to test it which implies adding mock client.
Canonical way do it is by dependency injection and interface:
class Cache
{
private IDhtClient client;
this(IDhtClient client) { this.client = client; }
}
And know what? This just plain sucks. Not only you are now forced
to modify yoru application code in many places to just comply to
test-related changes that don't help actual app. You also
introduce unnecessary interface indirection potentially killing
inlining opportunities in the process.
Same stuff with policy approach:
class CacheT(DhtClient)
{
static assert (isDhtClient!DhtClient);
private DhtClient client;
this(string addr) { this.client = new DhtClient(addr); }
}
alias Cache = CacheT!DhtClient;
Effectively the same code as sample 1 and makes no difference for
rest of the application. And how would I test it?
alias TestCache = CacheT!StubDhtClient;
No changes to application, no extra indirections, same effective
testing coverage. Much better.
And, of course, any utility functions that contain complex logic
are better moved to free functions so that those can be tested
with no relation to other code at all.