【问题标题】:How to mock a setter method using Mockito that has multiple parameters如何使用具有多个参数的 Mockito 模拟 setter 方法
【发布时间】:2017-08-02 12:11:22
【问题描述】:

我的问题是如何使用 Mockito 的 doAnswer 调用原始方法并使用我自己的测试参数。更复杂的是,其中一个参数不是原语。这是一个自定义类。

鉴于以下情况:

public class EnvironmentQualityStatus {
    public int environmentQuality = EnvironmentQualityStatus.NA;
    public long cht = -1;
    public int environmentSubType = -1;
    public String engineer="";
    public int engineerType = -1;
    public long timeStamp = 0;
    public static final String version = "tpv1";

    EnvironmentQualityStatus(){}

    EnvironmentQualityStatus(int environmentQuality, long cht, int environmentSubType, String engineer, int engineerType) {
        this.environmentQuality = environmentQuality;
        this.cht = cht;
        this.environmentSubType = environmentSubType;
        this.engineer = engineer;
        this.engineerType = engineerType;
        timeStamp = System.currentTimeMillis();
     }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("ts: ");
        sb.append(timeStamp);
        sb.append(", quality: ");
        sb.append(EnvironmentQualityStatus.valueOf(environmentQuality));
        sb.append(", cht: ");
        sb.append(cht);
        sb.append(", type: ");
        if (engineerType == Engineers.TYPE_CIVIL) {
            sb.append(“civil”);
        } else if (engineerType == Engineers.TYPE_INDUSTRIAL) {
            sb.append(“industrial”);
            if (!TextUtils.isEmpty(engineer)) {
                sb.append(", Engineer: ");
                sb.append(engineer);
             }
         } else {
             sb.append("n/a");
         }
         return sb.toString();
    }
}

利用上面的代码在类中设置一些东西。我想使用 Mockito 模拟这个调用(以及其他类似的调用)。

public class EnvironmentQuality {
...
public void updateEnvironmentQuality(EnvironmentQualityStatus eqStatus ,
                                      int environmentQuality ,int cht , String engineer, boolean notify ){
        //set some stuff....
    }
}

我知道使用 Mockito 的 doAnswer 是正确的方法。我只是不知道如何连接最后一部分,我用自己的方法操作调用的值,以便在测试运行时使用它们的程序得到我的值。我已经阅读了 Mockito 文档以及围绕该主题的几篇 SO 帖子,但我仍然不清楚。

EnvironmentQuality environmentQuality = spy((EnvironmentQuality)EnvironmentQuality.getInstance(context));

    spy(environmentQuality).updateNetworkQuality(Mockito.any(com.something.internal.EnvironmentQualityStatus.class), anyInt(), anyInt(), anyString(), anyBoolean());
    doAnswer(new Answer<Void>() {
        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {

            //This is an example of how to spy the parameters that were passed.
            EnvironmentQualityStatus status = (EnvironmentQualityStatus)invocation.getArguments()[0];

            int environmentQuality = (int)invocation.getArguments()[1];
            int cht = (int)invocation.getArguments()[2];
            String engineer = (String)invocation.getArguments()[3];
            boolean notify = (boolean)invocation.getArguments()[4];

            //But how to customize the parameters so that every time updateEnvironmentQuality(...) is called, a test can customize the params and dynamically influence the values.
            return null;
        }
    }).when(environmentQuality).updateEnvironmentQuality(Mockito.any(com.something.internal.EnvironmentQualityStatus.class), anyInt(), anyInt(), anyString(), anyBoolean());

【问题讨论】:

  • 您只能在 doAnswer 中更新 EnvironmentQualityStatus 参数,因为其余参数是不可变的。
  • 为什么是-1?我认为这个问题和你的答案可以向其他人澄清这一点。
  • 你的问题我不清楚。你是说你想要调用存根方法的真实版本,但是修改了参数的值?我不相信 Mockito 目前会这样做,但您可以提出功能请求。
  • @DawoodibnKareem,感谢您的添加。我已经更新了这个问题,希望能够为所有人澄清。

标签: java android unit-testing mockito functional-testing


【解决方案1】:

所以我假设您想用其他值调用该方法。通过检查InvocationOnMock 中的the documentation,您可以检查如何获取被调用的MethodObject。所以这应该很容易修改:

    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        Object callingObject = invocation.getMock();
        Method method = invocation.getMethod();
        method.invoke(callingObject, /* arguments... */);
        return null;
    }

【讨论】:

  • 我想补充一点。在您尝试代理该方法的情况下(就像我正在做的那样),我们最终会陷入递归调用情况。当我们使用自己的参数调用该方法时,我们最终会再次回到答案中。因此,解决方法是使用反射来获取 setter 方法正在设置的成员变量。因此,结果(对我们来说)是相同的,没有递归问题。您的里程可能会有所不同。
  • 你测试过这个吗?我不确定它会起作用。根据Methodinvoke 方法的Javadoc, "... 它是使用Java 语言规范,第二版,第15.12.4.4 节中记录的动态方法查找来调用的;特别是,基于覆盖的目标对象的运行时类型将发生..." 这意味着您只是在存根对象上再次调用该方法。所以你的answer 方法会反复调用自己,直到你的堆栈溢出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-07
  • 1970-01-01
  • 2020-12-08
  • 2015-12-13
  • 2016-10-23
相关资源
最近更新 更多