在不更改其他人的 class 的情况下,我如何要求它使用我的 Scanner 版本(作为内部 class 埋藏)而不是 java.util.Scanner?
Without altering another person's class, how can I require it to use my version of Scanner (buried as an inner class) instead of java.util.Scanner?
为了好玩(并在我的 class 房间中用作教学工具),我正在编写一个类似于 JUnitTests 的程序。我想用它来 运行 测试高中生编写的代码。当学生使用扫描仪编写通过 System.in 获取用户输入的代码时,我想 "hijack" 扫描仪提供我自己的预定用户输入。除了我希望我的扫描仪成为 AutoTester 的内部 class 之外,我的一切都很好。
下面的例子过于简单化了,但明白了要点。
假设一个学生写了这段代码:
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 的 class,它看起来像这样的伪代码:
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 之前使用我的(本地)扫描仪。但是,当我将我的扫描仪作为内部 class 移动到 AutoTester 时,学生代码不知道去那里寻找它。而且我不想以任何方式编辑学生代码(例如将 Scanner 实例化行更改为 new AutoTester.Scanner(System.in))
当 compiling/running 学生的程序不对他们的代码进行任何编辑时,有什么方法可以让我的 AutoTester.Scanner 优先于 java.util.Scanner?
不幸的是,那样行不通。自定义扫描器的 class 名称实际上是 AutoTester.Scanner
,您在测试 class 中定义了它,除了看起来相似之外它与 java.util.Scanner 无关。所以这根本不会影响 Practice
。
您必须重组 Practice
代码以使用 @Inject
s(例如 CDI) for something that works as a scanner. Then use mockito (@Mock, @InjectMocks)连接您的扫描仪。不过,那是很多重型机械。作为替代方案,您可以设计 Practice
以便它将 Scanner 作为构造函数参数或作为 属性.
但是问题仍然存在,即扫描仪是最终的 class,无法扩展。因此,您必须为此目的引入自己的界面,在一种情况下将 java.util.Scanner 置于引擎盖下,而在另一种情况下将您的替代扫描仪置于其中。
为了好玩(并在我的 class 房间中用作教学工具),我正在编写一个类似于 JUnitTests 的程序。我想用它来 运行 测试高中生编写的代码。当学生使用扫描仪编写通过 System.in 获取用户输入的代码时,我想 "hijack" 扫描仪提供我自己的预定用户输入。除了我希望我的扫描仪成为 AutoTester 的内部 class 之外,我的一切都很好。
下面的例子过于简单化了,但明白了要点。
假设一个学生写了这段代码:
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 的 class,它看起来像这样的伪代码:
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 之前使用我的(本地)扫描仪。但是,当我将我的扫描仪作为内部 class 移动到 AutoTester 时,学生代码不知道去那里寻找它。而且我不想以任何方式编辑学生代码(例如将 Scanner 实例化行更改为 new AutoTester.Scanner(System.in))
当 compiling/running 学生的程序不对他们的代码进行任何编辑时,有什么方法可以让我的 AutoTester.Scanner 优先于 java.util.Scanner?
不幸的是,那样行不通。自定义扫描器的 class 名称实际上是 AutoTester.Scanner
,您在测试 class 中定义了它,除了看起来相似之外它与 java.util.Scanner 无关。所以这根本不会影响 Practice
。
您必须重组 Practice
代码以使用 @Inject
s(例如 CDI) for something that works as a scanner. Then use mockito (@Mock, @InjectMocks)连接您的扫描仪。不过,那是很多重型机械。作为替代方案,您可以设计 Practice
以便它将 Scanner 作为构造函数参数或作为 属性.
但是问题仍然存在,即扫描仪是最终的 class,无法扩展。因此,您必须为此目的引入自己的界面,在一种情况下将 java.util.Scanner 置于引擎盖下,而在另一种情况下将您的替代扫描仪置于其中。