如何测试类方法是否正在从类的私有对象之一调用另一个方法

时间:2019-05-31 23:40:15

标签: java unit-testing method-call

我正在尝试为一个项目创建单元测试。在我的项目中,我有一个菜单类和一个VerticalOptions类。

我的菜单类有一个私有的VerticalOptions对象和一个公共的handleInput方法。 当我调用菜单的handleInput(key)方法时,根据我提供的键,它将执行不同的操作,即调用VerticalOptions对象的不同方法。

我想做一个unitTest来查看被调用的方法是否正确,该怎么办?

我尝试将Mockito间谍添加到菜单中,但是由于我想测试被调用的方法是否是私有VerticalOptions对象中的方法,因此它实际上不起作用。

在使用getVerticalOptions方法获取间谍之后,我还尝试将间谍放置在VerticalOptions对象上,但是它也不起作用。

public void handleInput(InputKey key)
{
    switch (key) {
        case S:
        case DOWN:
            optionsInterface.cycleDown();
            break;
        case W:
        case UP:
            optionsInterface.cycleUp();
            break;
        case SPACE:
        case ENTER:
            optionsInterface.select();
            break;
        default:
            break;
    }
}


@Test
public void testInput() {
    MainMenu menu = new MainMenu(game);
    VerticalButtonInterface buttonInterface = menu.getOptionsInterface();
    VerticalButtonInterface spy = spy(buttonInterface);

    menu.handleInput(InputKey.DOWN);
    verify(spy, times(1)).cycleDown();
}

这是我遇到的测试失败:

想要但不被调用: verticalButtonInterface.cycleDown(); ->在MenuTest.testInput(MenuTest.java:60) 实际上,与该模拟游戏的互动为零。

1 个答案:

答案 0 :(得分:1)

在这方面,我将为您提供另一种观点。我已经看到很多人走错了路,当您这样做时,其他所有事情都会变得难以执行/测试,这正是您现在正在做的事情。

从这里开始,您要达到什么目标?

  

我要测试并确保某个方法称为...

这是好事吗?什么不是单元测试?那就是对代码的深入了解。

为什么?因为每次您对代码进行微小的更改时,由于这些深厚的知识,您都必须更改测试。如果您有1000项测试,那您将步履维艰。

好,现在我们知道了问题所在,那么如何解决呢?好吧,首先让我们确保无需进行深入的代码测试就可以进行测试。

我们该怎么做?好吧,假设您的代码添加了一个额外的步骤,即设置状态的标志。您可能有一个存储结果状态的标志...

您要调用3个方法,因此需要3个不同的状态,因此请创建一个反映该变量的变量,它可以是字符串,枚举或其他使您满意的变量。

例如,假设我们创建一个具有3个可能值的字符串:cycleDown,cycleUp和select。

您的代码开始看起来像:

public string handleInput(InputKey key)
{
      String state = determineState(key);
      SomeType someResult = executeActionForState(state);
}

public String determineState(string key)
{

    String state = "";
     switch (key) {
    case S:
    case DOWN:
        state = "cycleDown";
        break;
    case W:
    case UP:
        state = "cycleUp";
        break;
    case SPACE:
    case ENTER:
        state = "select";
        break;
    default:
        break;
}

return state;
}

public void executeActionForState(string state)
{
     if ( state == "cycleup" ) {
     }

     etc etc
}

现在,我不一定要像这样编写您的示例,这有点强迫,它取决于您对代码执行的其他操作,但这旨在说明如何将功能与UI方面分开。

我可以轻松地测试状态方法,可以更改其代码,而不必更改测试,因为该测试将查看输入和输出,而不是如何实现。

单元测试是关于功能的,它是关于简单的测试,一旦创建就不需要更改。验证方法已被调用不会给您带来任何价值,因为您不知道该方法以后会做什么。

您可以通过其他方式测试的

UI内容,单元测试仅与正确的功能有关。如果您没有明确区分,那么您将难以维护测试,在您放弃测试之前,它将越来越难。

您将测试您是否获得了正确的状态,然后测试了cycleUp方法根据您的要求执行了一些正确的操作,这就是您知道每个部分独立工作的方式。稍后,您开始研究集成测试,自动UI测试,但这是不同的。保持单元测试的目的,保持简单,使其不与其他代码绑定,然后一切都变得简单。您无需进行太多模拟,也不必为复杂的设置担心太多,也不必每次代码更改时都更改测试。

现在,要解决问题的最后一部分,私有方法,您可以通过观察它们的输出来对其进行测试。您必须在类中拥有一些公共的东西,这些东西在调用私有方法时会发生变化。所以测试一下。