Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write JUnit for Adapter without overcomplicated code?

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?

like image 358
jk_ Avatar asked Nov 05 '22 17:11

jk_


1 Answers

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.

like image 137
Nick Holt Avatar answered Nov 09 '22 12:11

Nick Holt