Pav*_*vel 5 java junit unit-testing system.in java.util.scanner
你能解释一下如何System.in正确模拟吗?
我有一个简单的测试,我将值分配给
@Test
public void testBarCorrect() {
System.setIn(new ByteArrayInputStream("7\n2\n3".getBytes()));
someService().consume();
}
Run Code Online (Sandbox Code Playgroud)
在引擎盖下我什么都不做 new Scanner(System.in);
需要注意的是,有时我的测试是绿色的,但在 80% 时它会抛出一个 Exception "java.util.NoSuchElementException: No line found".
所以,如果我在测试中按下运行,它就会出现异常。
你能给我任何提示吗?
我的测试:
public class RecordServiceCTLIntegrationTest {
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final PrintStream originalOut = System.out;
private static final InputStream DEFAULT_STDIN = System.in;
@Before
public void setUpStreams() {
System.setOut(new PrintStream(outContent));
System.setIn(DEFAULT_STDIN);
}
@After
public void rollbackChangesToStdin() {
System.setOut(originalOut);
System.setIn(DEFAULT_STDIN);
}
@Test
public void testBarCorrect() {
System.setIn(new ByteArrayInputStream("5\n1\nB\n21\n\n".getBytes()));
buildRecordServiceCTL().run();
assertEquals("Enter Room Id: No active booking for room id: 5\n" +
"Enter Room Id: B:\tBar Fridge\n" +
"R:\tRestaurant\n" +
"S:\tRoom Service\n" +
"Enter service typeEnter cost: Service Bar Fridge has been added for the roomNumber 1\n" +
"Hit <enter> to continuePay for service completed\n", outContent.toString());
}
@Test
public void testRestaurantCorrect() {
System.setIn(new ByteArrayInputStream("5\n1\nR\n21\n\n".getBytes()));
buildRecordServiceCTL().run();
assertEquals("Enter Room Id: No active booking for room id: 5\n" +
"Enter Room Id: B:\tBar Fridge\n" +
"R:\tRestaurant\n" +
"S:\tRoom Service\n" +
"Enter service typeEnter cost: Service Restaurant has been added for the roomNumber 1\n" +
"Hit <enter> to continuePay for service completed\n", outContent.toString());
}
@Test
public void testRoomServiceCorrect() {
System.setIn(new ByteArrayInputStream("5\n1\nS\n21\n\n".getBytes()));
buildRecordServiceCTL().run();
assertEquals("Enter Room Id: No active booking for room id: 5\n" +
"Enter Room Id: B:\tBar Fridge\n" +
"R:\tRestaurant\n" +
"S:\tRoom Service\n" +
"Enter service typeEnter cost: Service Room Service has been added for the roomNumber 1\n" +
"Hit <enter> to continuePay for service completed\n", outContent.toString());
}
@Test(expected = NoSuchElementException.class)
public void testRoomException() {
System.setIn(new ByteArrayInputStream("-1\n\n".getBytes()));
buildRecordServiceCTL().run();
}
@Test
public void cancel() {
System.setIn(new ByteArrayInputStream("5\n1\nS\n20\n".getBytes()));
assertEquals("", outContent.toString());
}
private RecordServiceCTL buildRecordServiceCTL() {
Hotel hotel = new Hotel();
final Guest guest = new Guest("name", "address", 123);
final Room room = new Room(1, SINGLE);
final CreditCard card = new CreditCard(VISA, 123, 123);
final Booking booking = new Booking(guest, room, new Date(), 10, 1, card);
hotel.activeBookingsByRoomId.put(room.getId(), booking);
final Map<Integer,Room> map = new HashMap<>();
map.put(room.getId(), room);
hotel.roomsByType.put(SINGLE, map);
return new RecordServiceCTL(hotel);
}
}
Run Code Online (Sandbox Code Playgroud)
异常发生在 run 方法中:
if (stdin == null) {
stdin = new Scanner(System.in);
}
String ans = stdin.nextLine();
Run Code Online (Sandbox Code Playgroud)
这个测试对我来说效果很好:
@Test
public void testBarCorrect() {
System.setIn(new ByteArrayInputStream("7\n2\n3".getBytes()));
Scanner scanner = new Scanner(System.in);
System.out.println(scanner.nextLine());
System.out.println(scanner.nextLine());
System.out.println(scanner.nextLine());
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我添加以下测试,则会失败:
@Test
public void testFooCorrect() {
Scanner scanner = new Scanner(System.in);
System.out.println(scanner.nextLine());
System.out.println(scanner.nextLine());
System.out.println(scanner.nextLine());
}
java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Scanner.java:1540)
at com.amazon.adcs.service.dra.domain.A9DeviceTest.testFooCorrect(A9DeviceTest.java:15)
Run Code Online (Sandbox Code Playgroud)
理论上,单元测试应该让 JVM 保持与执行测试之前相同的状态。这不是你的情况,因为你已经改变了单例状态,并且在测试后你不会回滚修改。如果您有多个使用 的测试System.in,则第一个测试可能会消耗掉所有测试,而不会为另一个测试留下任何内容。
通常,我建议您InputStream在类中注入 an ,然后您可以自由地做任何您想做的事情,而不会影响系统常量。既然您告诉我您无法编辑代码,那么您应该确保自己清理状态。
像这样的事情就可以解决问题:
private static final InputStream DEFAULT_STDIN = System.in;
@After
public void rollbackChangesToStdin() {
System.setIn(DEFAULT_STDIN);
}
Run Code Online (Sandbox Code Playgroud)
如果您必须经常这样做,您可能需要考虑实施JUnit 规则。