为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

红糖糍粑 2022-12-28 10:50:29
我正在尝试为项目创建单元测试。在我的项目中,我有一个菜单类和一个 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;    }}@Testpublic 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 回答

?
江户川乱折腾

TA贡献1851条经验 获得超5个赞

我会给你另一种观点。我见过很多人走错了路,当你这样做时,其他一切都变得很难做/测试,这正是你现在正在做的。


从这里开始,你想达到什么目的?


我想测试并确保某个方法被调用......


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


为什么?因为每次你对代码做一点小改动,你都会因为这种深厚的知识而不得不改变测试。如果您有 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 测试,但这些是不同的东西。对它的目的进行单元测试,保持简单,不与其他代码绑定,然后一切都会变得简单。你不需要模拟太多,你不需要太担心复杂的设置,你也不需要每次代码中的某些内容发生变化时都改变你的测试。


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


查看完整回答
反对 回复 2022-12-28
  • 1 回答
  • 0 关注
  • 72 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信