java - 模拟抽象类中的新对象实例

标签 java junit mockito

我有一个 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 类正在扩展 Abstract 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);
}

最佳答案

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

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

@RunWith(PowerMockRunner.class)

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

这个特定的问题仍然可以通过运行最新版本的电源模拟作为 JUnit 的规则来解决(我假设您运行 JUnit)您可以找到一个执行此操作的示例 here 但最重要的是,这是电源模拟的已知问题之一。

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

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

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

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

  • 即使 IntelliJ 有时也无法运行包含强大模拟测试的套件。

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

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

建议您观看 Misko Hevery 的精彩讲座 about clean code为了更好地理解我的意思

再说一次,在你的例子中。最好将 ForceApi 维护为依赖注入(inject)框架构建的依赖项(我看到您已经使用 @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
  }    
}

现在,对于单元测试,您不再需要电源模拟了。根据情况使用简单的 Mock 甚至 Stub 就足够了。您所需要的只是提供一个构造函数,该构造函数将采用 ForceApi 类型的参数,或者可能是一个 setter(您可以考虑将其封装为私有(private),以便没有人能够在测试之外调用它)。

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

希望这有帮助

关于java - 模拟抽象类中的新对象实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34399767/

相关文章:

java - JAI 将 byte[] 保存到 .tiff 文件

java - <c :foreach> to show list

Java - Spring Integration Mock SftpServer 错误

java - Mockito Verify 方法如何工作?

java - 与交易模板集成测试手动交易

java - 使用接口(interface)名称将 jar 添加到 java 应用程序

java.lang.NoSuchMethodError : javaxservlet. http.HttpServletRequest.isAsyncStarted()Z

java - Junit 5,Spring 应用程序上下文未在 @DirtiesContext 上关闭

android - 如何运行协程作为单元测试的阻塞?

目录中的 Java JTree(显示完整路径,而不仅仅是文件名)