I have an adapter from I1
to ILogger
implemented like this:
class BAdapter() implements I1
{
void logA() { // nothing }
void logB() { new BLogger().log() }
void logC() { // nothing }
}
I would like to write JUnit test, that verify the functionality, but I found it a bit problematic, since I cannot inject my Mock object instead of BLogger
, or verify return value. I found several possible solution, but I am not sure, which is the best.
Case One:
Add void setLogger(Logger l)
to the BAdapter
class.
class BAdapter() implements I1
{
private Logger logger = new BLogger();
public void logB() { logger.log() }
public void setLogger(Logger l) { logger = l }
.. //rest of methods
}
Cons: Why to add setter which is never used in "real", non-testing code?
Case Two:
Add protected factory method and sublcass BAdapter
in test package.
class BAdapter() implements I1
{
public void logB() { createLogger().log() }
protected Logger createLogger() { retrun new BLogger() }
.. //rest of methods
}
class BAdapterForTesting extends BAdapter()
{
protected Logger createLogger() { retrun new MockBLogger() }
}
Cons: I am not sure, if this is clean and elegant solution, but I don't see much cons here.
Case Three: Use Abstract Factory pattern.
class BAdapter() implements I1
{
public void logB() { AbstractFactory.getFactory().getBLogger().log() }
.. //rest of methods
}
And somewhere in tests:
AbstractFactory.setFactory(new MockLoggersFactory())
Cons: This is too complex, isn't it?
Case Four: Return Boolean, for example, when logging was performed. E.g.
class BAdapter() implements I1
{
Boolean logA() { return false; }
Boolean logB() { return new BLogger().log() }
Boolean logC() { return false; }
}
Cons: This is kind of wourkaround. Why to return some value, when nobody needs it in "real", non-testing code?
Better Solution? Is there anything better?
From your code it's hard to tell exactly what the class under test is trying to achieve but I'd go with Case One with the caveat that I'd use injection in the 'real' code too.
One of the benefits of injection is it makes the class, in this case your adapter, more re-usable. Forcing the logB
method to always delegate to an instance of BLogger
sets that behaviour in stone at compile time. If I want the adapter to delegate to another type of Logger
I can't use it and it is therefore slightly less re-usable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With