Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用扫描器对用户输入进行junit测试_Java_Junit_Mocking_Mockito - Fatal编程技术网

Java 使用扫描器对用户输入进行junit测试

Java 使用扫描器对用户输入进行junit测试,java,junit,mocking,mockito,Java,Junit,Mocking,Mockito,我必须在一个类中测试一个方法,该类使用Scanner类接受输入 package com.math.calculator; import java.util.Scanner; public class InputOutput { public String getInput() { Scanner sc = new Scanner(System.in); return sc.nextLine(); } } 我想用JUnit测试它,但不确定如何

我必须在一个类中测试一个方法,该类使用Scanner类接受输入

package com.math.calculator;

import java.util.Scanner;

public class InputOutput {

    public String getInput() {
        Scanner sc = new Scanner(System.in);
        return sc.nextLine();
    }
}
我想用JUnit测试它,但不确定如何做

我尝试使用下面的代码,但它不起作用

package com.math.calculator;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class InputOutputTest {

    @Test
    public void shouldTakeUserInput() {
        InputOutput inputOutput= new InputOutput();

        assertEquals("add 5", inputOutput.getInput());
    }
}

我还想用Mockito(使用mock…when…然后return)来尝试它,但不确定如何操作。

您可以使用
System.setIn()方法在
流中更改
系统

试试这个

@Test
public void shouldTakeUserInput() {
    InputOutput inputOutput= new InputOutput();

    String input = "add 5";
    InputStream in = new ByteArrayInputStream(input.getBytes());
    System.setIn(in);

    assertEquals("add 5", inputOutput.getInput());
}
您刚刚在
字段中修改了
系统
System.in
基本上是一个
InputStream
,它从
控制台
读取(因此您在控制台中的输入)。但您只是修改了它,让系统从提供的
inputstream
读取。因此,它不再从控制台读取,而是从提供的输入流中读取。

< P>除了,还提到了重构,考虑重构,因此<代码> GETINPUT()/代码>变成了一个单行调用,调用一个完整的<代码> GETINPINT(扫描器)< /C> >方法,您可以通过创建自己的<代码> Scanner(“您的\Nest\\NoPIN\\N”)轻松地进行测试。
。还有许多其他方法可以注入扫描仪依赖项,比如创建一个覆盖的字段以进行测试,但只需创建一个方法重载就非常简单,从技术上来说,它可以为您提供更大的灵活性(例如,允许您添加一个功能来读取文件中的输入)

一般来说,请记住设计时要考虑测试的方便性,并且高风险部件的测试要比低风险部件的测试更重。这意味着重构是一个很好的工具,测试
getInput(Scanner)
可能比测试
getInput()
重要得多,尤其是当您不仅仅是调用
nextLine()


我强烈建议不要创建模拟扫描器:模拟您不拥有的类型不仅是一种不好的做法,而且扫描器代表了一个非常大的相关方法API,调用顺序很重要。在Mockito中复制它意味着要么在Mockito中创建一个大的假扫描程序实现,要么模拟一个只测试所做调用的最小实现(如果实现发生更改,即使您的更改提供了正确的结果,也会中断)。使用真正的扫描器并保存Mockito实践,以用于外部服务调用或模拟您定义的小型但未编写的API的情况。

首先,我假设测试的目标是验证用户输入是否从扫描器获得,返回的值是否是扫描器中输入的值

模拟不起作用的原因是每次都在
getInput()
方法中创建actual扫描仪对象。因此,无论您做什么,都不会调用mockito实例。因此,使该类可测试的正确方法是识别该类的所有外部依赖项(在本例中,
java.util.Scanner
并通过构造函数将它们注入类中。通过这种方式,您可以在测试期间注入模拟扫描仪实例。这是实现依赖项注入的基本步骤,而依赖项注入反过来又会导致良好的TDD。示例将帮助您:

 package com.math.calculator;

    import java.util.Scanner;

    public class InputOutput {

        private final Scanner scanner;

        public InputOutput()
        {
           //the external exposed default constructor 
           //would use constructor-chaining to pass an instance of Scanner.

           this(new Scanner(System.in));
        }

        //declare a package level constructor that would be visible only to the test class. 
      //It is a good practice to have a class and it's test within the same     package.
        InputOutput(Scanner scanner)
        {
            this.scanner  = scanner;
        }

        public String getInput() {

            return scanner.nextLine();
        }
    }
现在,您的测试方法:

@Test
public void shouldTakeUserInput() {
    //create a mock scanner
    Scanner mockScanner = mock(Scanner.class);
    //set up the scanner
    when(mockScanner.nextLine()).thenReturn("add 5");

    InputOutput inputOutput= new InputOutput(mockScanner);

    //assert output
    assertEquals("add 5", inputOutput.getInput());

   //added bonus - you can verify that your scanner's nextline() method is
   //actually called See Mockito.verify
   verify(mockScanner).nextLine();
}
还要注意的是,由于在上面的类中我使用构造函数进行注入,所以我将Scanner实例声明为final。因为我在这个类中没有更多的可变状态,所以这个类是线程安全的


基于构造函数的依赖注入的概念非常酷,值得在互联网上阅读。它有助于开发良好的线程安全可测试代码。

您可以使用库的
TextFromStandardInputStream
规则为命令行界面编写清晰的测试


成功了:)。您能告诉我这是如何工作的吗?优秀的解决方案可能是迄今为止最好的方法的重复,尽管它需要@Stefan您的解决方案工作得很好,添加此依赖项,您就可以开始了!
`com.github.stefanbirkner`
系统规则
1.16.0
S不能嘲笑罐头商,因为该类是最终类。
public void MyTest {
  @Rule
  public final TextFromStandardInputStream systemInMock
    = emptyStandardInputStream();

  @Test
  public void shouldTakeUserInput() {
    systemInMock.provideLines("add 5", "another line");
    InputOutput inputOutput = new InputOutput();
    assertEquals("add 5", inputOutput.getInput());
  }
}