简体   繁体   English

如何在mockito测试用例中模拟控制台用户输入

[英]How to mock console user input in mockito test cases

I want to mock the console input in test cases under junit/mockito can any one please help me. 我想在junit / mockito下的测试用例中模拟控制台输入,任何人都可以帮助我。 My source code: 我的源代码:

ConsoleSrc.java ConsoleSrc.java

import java.io.Console;

public class ConsoleSrc {
    public static String readFromConsole() {
    String str = null;
    try {  
      Console con = System.console();              
      System.out.println("The console object is: " + con);                        
      str = con.readLine();
      System.out.println("String is : " + str);
    } catch (Exception ex) {
      ex.printStackTrace();
    }

    return str;
  }

  public static void main(String[] args) {
      ConsoleSrc cs = new ConsoleSrc();
      String str = cs.readFromConsole();
      System.out.println("String is : " + str);
  }
}

Test code ConsoleTest.java 测试代码ConsoleTest.java

import org.junit.Test;
import static org.junit.Assert.*;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class ConsoleTest {

@Test
public void ConsoleSrcTestSuccess() {

    ConsoleSrc cs =  mock(ConsoleSrc.class);
    when(cs.readFromConsole()).thenReturn("##This is not console##");
    assertEquals(cs, "This is not console");
  }
}

The other answer is correct, but in the end, you are rather looking at a "design" problem here; 另一个答案是正确的,但最后,你更倾向于看一个“设计”问题; and fixing that will make your code much easier to test. 并修复将使您的代码容易测试。

Your problem originates from the fact that you want to test the System console. 您的问题源于您要测试系统控制台的事实。 But that is ... actually a bad idea. 但那......实际上是一个主意。

You see, in the end, you will want to make sure that one part of your program has a "source" where it can "read" information from. 你会看到,最后,你需要确保你的程序的一部分有一个“源”,它可以从中“读取”信息。 You "fixated" that source to be the console. 您“固定”了该源作为控制台。 That seems logical but is actually wrong . 这似乎合乎逻辑但实际上是错误的

You want to abstract from specific implementations; 您希望从特定实现中抽象出来; instead you want to use interfaces or "base classes" where possible. 相反,你想尽可能使用接口或“基类”。 For example: java.io.Reader . 例如: java.io.Reader If you do that, you could write your code as: 如果这样做,您可以将代码编写为:

public class ConsoleReader {
  private final Reader source;

  public ConsoleReader() { this ( System.console.reader() ); }
  ConsoleReader(Reader source) { this.source = source; }

The above allows you to: 以上允许您:

  • Create a ConsoleReader object using the default no-arg constructor; 使用默认的no-arg构造函数创建ConsoleReader对象; and then it will read from System.console 然后它将从System.console读取
  • But, you can also use the other constructor, and provide any kind of reader to your class under test. 但是,您也可以使用其他构造函数,并为您正在测试的类提供任何类型的读者。 For example: a mocked Reader, created by Mockito. 例如:由Mockito创建的模拟读者。

And now you don't have to mock a method in Console; 现在你不必在Console中模拟一个方法; but you mock Reader; 但你嘲笑读者; and are free to mock any method of that class! 并且可以自由地模仿该类的任何方法!

Long story short: you came up with an inflexible design, that is also hard to test. 长话短说:你想出了一个不灵活的设计,也很难测试。 The answer is not to circumvent that problem using mocking framework tricks; 答案是不要使用模拟框架技巧来规避这个问题; but to improve the design; 但要改进设计; so it can be tested easier! 所以它可以更容易测试!

Yes, the Console class is final , so Mockito can not directly mock it by creating a sub-class. 是的, Console类是final ,所以Mockito不能通过创建子类来直接模拟它。 To work around this, you have to isolate the interaction in another method or a wrapper class. 要解决此问题,您必须在另一个方法或包装类中隔离交互。 Then you mock this method or the wrapper. 然后你模拟这个方法或包装器。

The concrete problem in your code: You can not mock a static method. 代码中的具体问题:您无法模拟静态方法。 Just remove the static modifier from readFromConsole() . 只需从readFromConsole()删除static修饰符readFromConsole()

Some observations on your code example: 对您的代码示例的一些观察:

  • according to the Javadoc of System.console() it returns "The system console, if any, otherwise null.", so your production code should handle the null case. 根据System.console()的Javadoc,它返回“系统控制台,如果有的话,否则为null。”,所以你的生产代码应该处理null情况。
  • instead of using Console you could read from System.in which can be switched by eg System.setIn(new ByteArrayInputStream("This is not console".getBytes(StandardCharsets.UTF_8))); 而不是使用Console你可以从System.in读取,可以通过例如System.setIn(new ByteArrayInputStream("This is not console".getBytes(StandardCharsets.UTF_8)));切换System.setIn(new ByteArrayInputStream("This is not console".getBytes(StandardCharsets.UTF_8)));
  • the assertEquals call does not make sense for two reasons: assertEquals调用没有意义,原因有两个:
    • comparison of cs as an instance of ConsoleSrc with a String will always fail cs作为ConsoleSrc的实例与String将始终失败
    • assertions on a mocked return value would not test you code but the mocking framework 对模拟返回值的断言不会测试代码,而是测试模拟框架

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM