在不改变另一个人的类的情况下,我如何要求它使用我的 Scanner 版本而不是

为了好玩(并在课堂上用作教学工具),我正在编写一个类似于 JUnitTests 的程序。我想用它来对高中生编写的代码进行测试。当学生编写使用扫描仪通过 System.in 获取用户输入的代码时,我想“劫持”扫描仪以提供我自己预先确定的用户输入。除了我希望我的扫描仪成为自动测试仪的内部类之外,我一切都工作得很好。


下面的例子过于简单化了,但是很能说明问题。


假设一个学生写了这样的代码:


import java.util.*;

public class Practice {  

    public static void practiceScanners()  {

        Scanner console = new Scanner(System.in);                 

        System.out.print("Type first name, age, and address >> ");

        String name = console.next();

        int age = console.nextInt();

        String address = console.nextLine();

        System.out.println(name + " is " + age + " and lives at" + address + ".");

    }

}

然后,假设我有一个名为 AutoTester 的类,它看起来像这样的伪代码:


public class AutoTester {


    public main() {

        * use JavaCompiler from ToolProvider to compile Practice.java

        * use reflection to invoke Practice.practiceScanners()

             * (hopefully) have student code use my Scanner instead of java.util.Scanner

             * collect output of running the student code 

             * compare against expected output

    }


    //My version of Scanner is an inner class within AutoTester

    public class Scanner { 

        private String script = "Bob 13 42 Maple Drive";

        <* implementation not shown *>    

    }


}

如果我将我的 Scanner 版本移至其自己的 Scanner.java 文件中,则效果很好。学生代码在查看 java.util 之前使用我的(本地)扫描仪。但是,当我将扫描仪作为内部类移动到自动测试器中时,学生代码不知道在那里寻找它。我不想以任何方式编辑学生代码(例如更改扫描仪实例化行以表示新的 AutoTester.Scanner(System.in))


在编译/运行学生的程序而不对其代码进行任何编辑时,有什么方法可以使我的 AutoTester.Scanner 优先于 java.util.Scanner 吗?


呼如林
浏览 73回答 1
1回答

湖上湖

不幸的是,事实并非如此。自定义扫描仪的类名实际上是AutoTester.Scanner,您在测试类中定义了它,除了看起来相似的名称之外,它与 java.util.Scanner 无关。Practice所以这根本不影响。您必须重构Practice代码才能使用@Injects (例如使用CDI)作为扫描仪。然后使用mockito(@Mock,@InjectMocks)连接您的扫描仪。不过,这是很多重型机械。作为替代方案,您可以设计Practice为将 Scanner 作为构造函数参数或属性。但仍然存在问题,即 Scanner 是无法扩展的最终类。因此,您必须为此目的引入自己的接口,在一种情况下将 java.util.Scanner 放在引擎盖下,在另一种情况下将您的替代扫描仪放在引擎盖下。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java