【问题标题】:Test a void method with conditioned loop using mockito使用 mockito 测试带有条件循环的 void 方法
【发布时间】:2015-03-11 18:31:23
【问题描述】:

我有以下方法要求用户输入,直到输入有效的用户凭据。然后为该用户生成 id 并设置已注册 =TRUE。

1.如何检查单元测试中“注册”的局部变量的值?

2.如何在我的测试中断言 while 循环执行直到“注册”变为 TRUE?

private void register() {

    boolean registered=false;
    while(!registered){
        try {
            String uname =this.read("User Name : ");
            char password[] = this.readPassword();
            String serverURL = this.read("Server URL : ");

            if(!uname.isEmpty() && password!=null && !serverURL.isEmpty()){ 

                registered=this.getUID(uname,password,serverURL);
            }
            if(registered==false)
                System.out.println("\nPlease verify your details and try again!\n");

        } catch (UnsupportedEncodingException e) {} 
        catch(Exception e){}    
    }
    System.out.println("Successful");
}

我遇到过使用 ArgumentCaptor 来捕获要测试的方法用来调用另一个方法的变量。

e.g verify(mockObj).intArgumentMethod(argument.capture());

但是我没有将变量“注册”传递给任何其他方法,否则我会捕获它。

【问题讨论】:

  • 您可以使用reflections 进行验证。我认为为此您必须将其设为类级别变量而不是方法变量。不确定。
  • 在这种情况下,我需要将其设为类变量,但这不是一个选项

标签: java unit-testing junit mocking mockito


【解决方案1】:
  1. 你不能
  2. 通过验证:
    • 循环不变量是registered 为假。所以如果为真则不进入循环
    • 循环已退出
      • 在身体开始时(在这种情况下是真的)
      • 如果抛出 Throwable,则不会被“catch(Exception e)”捕获(在这种情况下,它可能是任何东西)

无论如何 - 检查您的测试策略:

  • 函数有输入参数和输出参数
  • 输入应该是夹具的一部分:

    this.read("User Name : ")
    this.readPassword()
    this.read("Server URL : ")
    this.getUID(uname,password,serverURL) // this may also be viewed as output
    
  • 输出应该是断言的一部分

    System.out.println(...)
    

可以通过创建匿名子类来设置输入,例如

fixture = new YourClass {
  public String read(String prompt) {
    return mockedString;
  }
  ...
};

可以通过 Junit 规则捕获/断言输出,例如StandardErrorStreamLog

此示例方法不需要 Mockito。

【讨论】:

  • 感谢@StefanA 我可以使用 StandardErrorStreamLog 测试积极的场景,如下所示: Whitebox.invokeMethod(pc,"register); assertEquals("Successful\n", log.getLog()) 。我该如何测试那个while循环执行了一定的次数?
  • 测试register 你不需要Whitebox。只需将方法设置为公开即可。关于循环步骤数的断言不应该接受单元测试。但是,您可以设置您的输入以使其步进多次。您可以使用TextFromStandardInputStream 来模拟您的用户输入 - 或者只是使用带有匿名子类化的解决方案。
【解决方案2】:

不要测试实现细节,测试给定输入的行为。如果registered 变量应该是某种输出,那么它不应该是局部变量。

我喜欢的一种设计是使用方法对象,可以在创建对象时传递参数,并且一个对象方法可以有多个返回值。

class Registrator {
    Registrator(...) { /* assigning needed field */ }

    void register() { /* logic that will mutate internal fields */ }

    boolean registered() { return registered; }
    long triesCount() { return triesCount; }
    // ...
}

并且可以修改代码以使用Report 对象,注册方法可以在该对象上附加成功/失败/更多详细信息,例如原因等。

而且测试会更容易编写。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 2021-01-16
    • 1970-01-01
    • 2019-08-18
    相关资源
    最近更新 更多