如何在没有过多复杂代码的情况下编写JUnit for Adapter?

jk_*_*jk_ 5 java junit mocking inversion-of-control adapter

我有一个适配器I1ILogger实现如下:

class BAdapter() implements I1
{
   void logA() { // nothing }
   void logB() { new BLogger().log() }
   void logC() { // nothing }
}
Run Code Online (Sandbox Code Playgroud)

我想编写JUnit测试,即验证的功能,但我发现它有点问题,因为我不能注入我的模仿对象,而不是BLogger,或验证返回值.我找到了几个可能的解决方案,但我不确定,哪个是最好的.

案例一: 添加void setLogger(Logger l)BAdapter类.

class BAdapter() implements I1
{
   private Logger logger = new BLogger();

   public void logB() { logger.log() }
   public void setLogger(Logger l) { logger = l }
   .. //rest of methods
}
Run Code Online (Sandbox Code Playgroud)

缺点:为什么要添加从未在"真实",非测试代码中使用过的setter?

案例二:BAdapter在测试包中 添加受保护的工厂方法和sublcass .

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() }
}
Run Code Online (Sandbox Code Playgroud)

缺点:我不确定,如果这是干净而优雅的解决方案,但我在这里看不太多.

案例三: 使用抽象工厂模式.

class BAdapter() implements I1
{
   public void logB() { AbstractFactory.getFactory().getBLogger().log() }
   .. //rest of methods
}
Run Code Online (Sandbox Code Playgroud)

在某些测试中:

AbstractFactory.setFactory(new MockLoggersFactory())
Run Code Online (Sandbox Code Playgroud)

缺点:这太复杂了,不是吗?

情况四: 返回布尔值,例如,执行日志记录时.例如

class BAdapter() implements I1
{
   Boolean logA() { return false; }
   Boolean logB() { return new BLogger().log() }
   Boolean logC() { return false; }
}
Run Code Online (Sandbox Code Playgroud)

缺点:这是一种wourkaround.为什么要在"真实",非测试代码中没有人需要它时返回一些价值?

改善方案? 有更好的吗?

Nic*_*olt 2

从您的代码中很难准确说出被测类试图实现的目标,但我会选择案例一,但需要注意的是,我也会在“真实”代码中使用注入。

注入的好处之一是它使类(在本例中为适配器)更可重用。强制logB方法始终委托给 的实例,BLogger从而在编译时设置该行为。如果我希望适配器委托给另一种类型,Logger我就无法使用它,因此它的可重用性稍差。