java - 如何在接口(interface)默认方法中对新对象创建进行单元测试?

标签 java unit-testing design-patterns junit

接口(interface)中有一个默认方法,用于创建新对象并使用其功能。所以我需要 mock 它。但如果不创建另一个返回新实例的默认方法,我就无法弄清楚。到目前为止,我曾经创建工厂来处理对象创建,而不是模拟工厂方法。但不能在接口(interface)中执行此操作,因为接口(interface)不能具有实例变量,在这种情况下,实例变量是工厂。还有其他想法吗?我希望在项目中保持一致,但现在我有两种不同的方法来避免在方法中创建对象。这是一个例子:

public interface ISomeInterface
{
    default Integer callMe( )
    {
        Object someObject = new Object( ); // need to mock this
        Integer result = someObject.finish();
        result = result + 1;

        return result;
    }
}

当我不使用这样的接口(interface)时,我曾经用工厂重构代码;

default Integer callMeNotInterfaceClass( )
{
    Object someObject = new Object( );
    Integer result = instanceFactory.create().finish(); // I can mock create() method 
    result = result + 1;

    return result;
}

我为包装方法实现的唯一解决方案:

public Integer callMe( )
{
    Object someObject = new Object( );
    Integer result = wrapperMethodCall.finish(); // only solution so far. But now I have 2 different approaches in the project to avoid object creation.
    result = result + 1;

    return result;
}

default Object wrapperMethodCall() {
    return new SomeObject().someMethodsToBeMocked();
}

最佳答案

像往常一样,单元测试迫使您考虑类的设计。

首先,您应该注意到有两种主要不同类型的对象。

一些对象是值:它们是不可变的,可以存在于多个副本中,是可比较的(并且也有一个hashCode)。这是一种很容易存储在数据库中的对象。如果您对 Kotlin 有一点了解,您就会听说过 data classes : 就是这样。

其他一些具有实体语义的对象:它们是可变的,比较它们没有意义,而且通常您只有它们的一个副本。它们是某事的对象。

具有实体语义的对象是您需要在单元测试中模拟的对象,而您不需要模拟值。要传递模拟,必须将这些对象作为构造函数的参数注入(inject)到类中。

在您的代码片段中,您在函数中创建了一个对象,该对象似乎具有实体的语义(值不会完成任何事情),这就是您遇到问题的原因:您可以' t 单元测试,因为您无法模拟此实体。

解决方案很简单:要么在方法中注入(inject)对象:

public interface ISomeInterface
{
    default Integer callMe(Object someObject)
    {
        Integer result = someObject.finish();
        result = result + 1;

        return result;
    }

    ...
}

或者你在类中注入(inject)对象:

public interface ISomeInterface
{
    default Integer callMe()
    {
        Integer result = finishObject();
        result = result + 1;

        return result;
    }

    // classes will need an instance of the object to implement this
    Integer finishObject(); 

    ...
}

在这两种情况下,实现接口(interface)的类都有责任在调用方法时提供对象本身,或者返回 finish 方法的值。

但请记住:如果您在这些类的方法中创建对象,则对它们进行单元测试也会变得困难。使用工厂模式在静态方法中创建实体对象并将这些对象传递给构造函数。

如果遵循以下经验法则,类和方法的单元测试将变得更容易:当对象具有语义值时,在更高级别创建它(如果可能的话,main)并传递它作为构造函数或方法的参数。

关于java - 如何在接口(interface)默认方法中对新对象创建进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57255321/

相关文章:

java - 如何测试线程之间值的可见性

java - Java语言规范中的位移位运算符描述

java - 无法加载(找到)j2v8_android_x86 库

java - 使用 spring security 根据用户角色设置自定义登录后目标

python - 如何测试或模拟 "if __name__ == ' __main_ _'"内容

javascript - 如何使用 async/await 使用 Jest 测试 mongoose 模型验证错误?

php - Symfony2 中的设计模式 : is EventDispatcher a Mediator or Event Aggregator?

javascript - 封装在javascript模块模式中

javascript - 使用事件在 View 设计模式之间进行通信

java - 如何使用两个 Multi-Tenancy 数据源之间的事务复制数据?