【问题标题】:Mock a New Object instance in a Abstract Class模拟抽象类中的新对象实例
【发布时间】:2015-12-21 16:02:54
【问题描述】:

我有一个 AbstractDao 类,我在其中实例化 Rest Fore API。我无法在 Power Mock 中模拟新的 forceAPI(config)。请提出建议。

public abstract class AbstractDao {

@Inject
private Configuration configuration;

public ForceApi getForceAPI() {
    ApiConfig config = new ApiConfig();
    config.setClientId("test");
    config.setClientSecret("test");
    config.setUsername("test");
    config.setPassword("test");
    config.setLoginEndpoint("test");
    return new ForceApi(config);
}

}

我正在尝试以这种方式进行操作,但它不起作用。 我的 DAO 类正在扩展抽象 DAO 类

@RunWith(BlockJUnit4ClassRunner.class)
public class SalesForceDaoImplTest {

@InjectMocks
private SalesForceDaoImpl salesForceDao;
@Mock
private ForceApi forceApiMock;
@Mock
private ApiConfig apiConfigMock;
@Mock
private Configuration configMock;
@Mock
JsonObject jsonobject;


@Before
public void setup() {
    initMocks(this);
    when(configMock.getAppConfiguration()).thenReturn(jsonobject);
    when(jsonobject.getString(anyString())).thenReturn("test");
    when(salesForceDao.getForceAPI()).thenReturn(forceApiMock);
    when(new ApiConfig()).thenReturn(apiConfigMock);
    when(new ForceApi(apiConfigMock)).thenReturn(forceApiMock);
}

【问题讨论】:

  • 不工作是什么意思?能具体一点吗?
  • 你可以看看this question。有一个示例说明如何使用PowerMockito 模拟构造函数

标签: java junit mockito


【解决方案1】:

这可能是一个迟到的回复,但我相信它对我们中的一些程序员仍然有用。

免责声明:我从未使用过 PowerMockito,但我使用过很多 PowerMock 至于 troig 的建议: PowerMock 驱动的单元测试假定您将使用专用的运行器运行:

@RunWith(PowerMockRunner.class)

在这种情况下,这与问题中所述的@RunWith(BlockJUnit4ClassRunner.class) 发生冲突,因此 RunWith 的“插槽”已被占用。

这个特殊的问题仍然可以通过运行最新版本的 power mock 作为 JUnit 的规则来解决(我假设你运行 JUnit)你可以找到一个这样做的例子here 但归根结底,这是 power mock 的已知问题之一。

还有其他问题,基本上让我得出结论,应该避免使用 power mock,并且不应该在新项目中使用(以及 Power Mockito):

  • 使用 power mock 的单元测试很慢(比使用 EasyMock 慢得多,如果它可以被重写)

  • Power Mock 有时会检测与 jacoco 代码覆盖等工具不兼容的字节码,因此声纳不涵盖使用 power mock 进行单元测试的类,或者至少是错误的

  • 负责在 maven 中运行测试的 Surefire 插件具有并行运行多个单元测试的功能。有时使用 power mock 是不可能的。

  • 即使是 IntelliJ 有时也无法运行包含电源模拟测试的套装。

但最重要的是,当您必须使用 power mock 之类的工具时,可能可以(并且应该)重构代码,使其更加干净和易于理解。关于您的特定问题:

你的类违反了类不应该处理自身依赖的编码原则。在这里,DAO 实际上“构建”并配置了另一个(外部)服务以供以后使用。

我建议你观看 Misko Hevery about clean code 的精彩讲座,以更好地理解我的意思

同样,在您的示例中。将ForceApi 维护为由依赖注入框架构建的依赖项要好得多(我看到你已经使用@Inject 所以你走在正确的轨道上)

看看这个实现:

public abstract class AbstractDao {

  @Inject // this one is constructed and injected by your favorite DI framework in real use cases
  private ForceApi forceApi;

  public void doSomething() {
       // do your dao stuff here
       forceApi.callSomeAPIMethod();
       // do your dao stuff here
  }    
}

现在对于单元测试,您不再需要 power mock。根据情况使用简单的 Mock 甚至 Stub 就足够了。您只需要提供一个构造函数,该构造函数将采用 ForceApi 类型的参数或者可能是一个 setter(您可以考虑将其设为包私有,这样任何人都无法在测试之外调用它)。

对于您的问题,我没有足够的信息,但我提供的设计可能可以消除对 DAO 的抽象类的需要,这在某些情况下也很有帮助,因为继承有时可以维持的相当沉重的“义务”(至少考虑一下)。也许在这种情况下,继承只是为了支持这种getForceAPI 行为。在这种情况下,随着项目的增长,可能会因为这样做方便而将一些方法添加到此 AbstractDAO 中,但此时这些方法将“透明地”添加到所有 DAO 的整个层次结构中。这种构造变得脆弱,因为如果至少有一种方法改变了它的实现,那么整个 DAO 层次结构可能会失败。

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-16
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多