Java EclEmma“;承保范围为「;Eclipse JUnit线程死亡
我使用TestFX编写了下面的JUnit4测试,以测试特定产品(待办事项列表)的GUI(JavaFX),以及两个必要的类。第一个类是管理整个GUI的主类,而第二个类是文本字段的类。如有必要,可以找到完整的源代码(它是已经提交的学校项目的一部分) 如果我在Eclipse中使用F11热键或者“RunAs->JUnit test”运行它,那么测试工作得非常好。然而,当我选择“覆盖率”时,它会在第一个测试用例上出现bug(不管我选择将哪个设置为第一个)。具体地说,它“键入”第一个测试用例的前两个字符(此处示例用例中的sh),然后告诉我检测到用户输入的错误(Java EclEmma“;承保范围为「;Eclipse JUnit线程死亡,java,eclipse,junit,eclemma,testfx,Java,Eclipse,Junit,Eclemma,Testfx,我使用TestFX编写了下面的JUnit4测试,以测试特定产品(待办事项列表)的GUI(JavaFX),以及两个必要的类。第一个类是管理整个GUI的主类,而第二个类是文本字段的类。如有必要,可以找到完整的源代码(它是已经提交的学校项目的一部分) 如果我在Eclipse中使用F11热键或者“RunAs->JUnit test”运行它,那么测试工作得非常好。然而,当我选择“覆盖率”时,它会在第一个测试用例上出现bug(不管我选择将哪个设置为第一个)。具体地说,它“键入”第一个测试用例的前两个字符(此
[TestFX]检测到用户鼠标移动。正在中止测试。
),然后移动到下一个测试用例
我一直无法自己解决这个问题,而且我在网上似乎也找不到多少帮助。任何帮助都将不胜感激!基于堆栈跟踪,它看起来与线程有关,但我看不出运行的覆盖率将如何导致这种情况(当正常测试不起作用时)
我必须缩短堆栈跟踪,因为我达到了极限
java.lang.RuntimeException: java.lang.ThreadDeath
at org.loadui.testfx.utils.FXTestUtils.awaitEvents(FXTestUtils.java:104)
at org.loadui.testfx.FXScreenController.release(FXScreenController.java:131)
at org.loadui.testfx.GuiTest.release(GuiTest.java:1110)
at org.loadui.testfx.GuiTest.type(GuiTest.java:1069)
at org.loadui.testfx.GuiTest.type(GuiTest.java:1008)
at org.loadui.testfx.GuiTest.type(GuiTest.java:990)
at gui.UserInterfaceTest.test1ShowUndoneEmpty(UserInterfaceTest.java:38)
Caused by: java.lang.ThreadDeath
at java.lang.Thread.stop(Unknown Source)
at org.loadui.testfx.utils.UserInputDetector.userInputDetected(UserInputDetector.java:58)
at org.loadui.testfx.utils.UserInputDetector.assertPointsAreEqual(UserInputDetector.java:42)
at org.loadui.testfx.utils.UserInputDetector.run(UserInputDetector.java:27)
at java.lang.Thread.run(Unknown Source)
UserInterface.java
package gui;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.scene.Scene;
import object.Task;
import type.CommandType;
import type.KeywordType;
import logic.FeedbackHelper;
import logic.LogicController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
//@@author A0112882H
public class UserInterface extends Application {
private static final int ROW_HEIGHT = 30;
private static BorderPane _root = new BorderPane();
private static Scene _defaultScene = new Scene(_root, 750, 580);
private static VBox _vbox = new VBox();
private static VBox _tables = new VBox();
private static UIButton _taskButton = new UIButton("Tasks & Events");
private static UIButton _floatingButton = new UIButton("Floating Tasks");
private static UITextField _field = new UITextField();
private static TextArea _cheatSheet = new TextArea();
private static Label _feedBack = new Label();
private static int commandIndex;
private static UITable _taskTable = new UITable(false);
private static UITable _floatingTable = new UITable(true);
private final KeyCombination _undoKey = new KeyCodeCombination(KeyCode.U, KeyCombination.CONTROL_DOWN);
private final KeyCombination _redoKey = new KeyCodeCombination(KeyCode.R, KeyCombination.CONTROL_DOWN);
private final KeyCombination _homeKey = new KeyCodeCombination(KeyCode.H, KeyCombination.CONTROL_DOWN);
private static ArrayList<String> commandHistory = new ArrayList<String>();
private static ArrayList<Task> _displayList = new ArrayList<Task>();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
_root.setOnKeyPressed(hotKeyEvents);
_field.setOnKeyPressed(hotKeyEvents);
setScene();
setUpCommandPrompt();
setUpTables();
setKeywordsHighlighting();
primaryStage.setScene(_defaultScene);
primaryStage.setTitle("F2DO");
primaryStage.show();
}
public BorderPane getRootNode() {
return _root;
}
private void setScene() {
String css = UserInterface.class.getResource("style.css").toExternalForm();
_defaultScene.getStylesheets().add(css);
_defaultScene.heightProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
int displaySize = (int) Math.floor(_taskTable.getHeight() / ROW_HEIGHT) - 1;
LogicController.setNonFloatingDisplaySize(displaySize);
updateDisplayList();
}
});
}
/**
* Set the hot keys. Ctrl + U: undo operation. Ctrl + R: redo operation.
* Ctrl + H: home page. F1: help page. F2: show all. F3: show undone tasks.
* F4: show done tasks. ESC: exit application.
*/
private EventHandler<KeyEvent> hotKeyEvents = new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
String showUndone = "show undone";
String showDone = "show done";
String showAll = "show all";
if (_undoKey.match(event)) {
String feedbackMsg = LogicController.undo();
_feedBack.setText(feedbackMsg);
updateDisplayList();
} else if (_redoKey.match(event)) {
String feedbackMsg = LogicController.redo();
_feedBack.setText(feedbackMsg);
updateDisplayList();
} else if (_homeKey.match(event)) {
initialiseScene();
setUpCommandPrompt();
setUpTables();
} else if (event.getCode().equals(KeyCode.F3)) {
String feedbackMsg = LogicController.process(showUndone, _displayList);
_feedBack.setText(feedbackMsg);
updateDisplayList();
} else if (event.getCode().equals(KeyCode.F4)) {
String feedbackMsg = LogicController.process(showDone, _displayList);
_feedBack.setText(feedbackMsg);
updateDisplayList();
} else if (event.getCode().equals(KeyCode.F2)) {
String feedbackMsg = LogicController.process(showAll, _displayList);
_feedBack.setText(feedbackMsg);
updateDisplayList();
} else if (event.getCode().equals(KeyCode.F1)) {
try {
initialiseScene();
setUpCommandPrompt();
setCheatSheetContent();
} catch (Exception e) {
}
} else if (event.getCode().equals(KeyCode.ESCAPE)) {
exit();
} else if (event.getCode().equals(KeyCode.ENTER)) {
String userInput = _field.getText();
commandHistory.add(userInput);
commandIndex = commandHistory.size() - 1;
_field.clear();
event.consume();
String feedbackMsg = LogicController.process(userInput, _displayList);
if (feedbackMsg == FeedbackHelper.MSG_HELP) {
try {
initialiseScene();
setUpCommandPrompt();
setCheatSheetContent();
} catch (Exception e) {
e.printStackTrace();
}
} else if (feedbackMsg == FeedbackHelper.MSG_HOME) {
initialiseScene();
setUpCommandPrompt();
setUpTables();
} else {
_feedBack.setText(feedbackMsg);
updateDisplayList();
}
} else if (event.getCode().equals(KeyCode.UP)) {
if (!commandHistory.isEmpty()) {
_field.replaceText(commandHistory.get(commandIndex));
int length = commandHistory.get(commandIndex).length();
commandIndex--;
Platform.runLater(new Runnable() {
@Override
public void run() {
_field.positionCaret(length);
}
});
if (commandIndex < 0) {
commandIndex = 0;
}
}
} else if (event.getCode().equals(KeyCode.DOWN)) {
_field.showPopup();
}
}
};
/**
* Set up command prompt and feedback
*/
private void setUpCommandPrompt() {
setTextArea();
setFeedback();
_field.setId("textarea");
_feedBack.setId("feedback");
_vbox.setAlignment(Pos.CENTER);
_vbox.setSpacing(5);
_vbox.getChildren().addAll(_field, _feedBack);
BorderPane.setMargin(_vbox, new Insets(20, 20, 0, 20));
_root.setTop(_vbox);
}
/**
* Set up labels and tables
*/
private void setUpTables() {
updateDisplayList();
BorderPane.setMargin(_tables, new Insets(8, 20, 30, 20));
BorderPane.setAlignment(_tables, Pos.CENTER);
_floatingTable.setId("floatingTable");
_taskTable.setId("taskTable");
_taskButton.setMaxWidth(Double.MAX_VALUE);
_floatingButton.setMaxWidth(Double.MAX_VALUE);
_taskButton.setStyle("-fx-font-size: 13.5; -fx-font-weight: bold");
_floatingButton.setStyle("-fx-font-size: 13.5; -fx-font-weight: bold");
_tables.setAlignment(Pos.CENTER);
_tables.getChildren().addAll(_taskButton, _taskTable, _floatingButton, _floatingTable);
_tables.setSpacing(7);
_root.setCenter(_tables);
}
/**
* Update tables.
*/
private static void updateDisplayList() {
ArrayList<Task> nonFloatingList = LogicController.getNonFloatingList();
ArrayList<Task> floatingList = LogicController.getFloatingList();
_displayList.clear();
_displayList.addAll(nonFloatingList);
_displayList.addAll(floatingList);
_taskTable.updateTable(nonFloatingList, floatingList);
_floatingTable.updateTable(nonFloatingList, floatingList);
_field.updateDisplayList(_displayList);
}
/**
* Set the design of textArea
*/
private void setTextArea() {
_field.setPrefHeight(25);
_field.setMaxHeight(25);
_field.setPadding(new Insets(2, 2, 2, 2));
_field.setWrapText(true);
_field.setStyle("-fx-border-color: lightblue; -fx-font-size: 14");
}
/**
* Set the design of feedback.
*
* @param feedback
*/
private void setFeedback() {
_feedBack.setText("Welcome to F2DO, your personalised task manager(:\n" + "Type " + "\"Help\""
+ " for a list of commands to get started.");
_feedBack.setMouseTransparent(true);
}
/**
* Set highlighting of the keyword.
*/
private void setKeywordsHighlighting() {
_field.textProperty().addListener((observable, oldValue, newValue) -> {
// check if the first word is a keyword - happens in most cases
// for commands e.g. like add, search, edit, delete
String firstWord = getFirstWord(newValue);
if (isValidCmd(firstWord)) {
_field.setStyle(0, firstWord.length(), "-fx-font-weight: bold; -fx-fill: red");
if (newValue.length() > firstWord.length()) {
_field.setStyle(firstWord.length() + 1, newValue.length(),
"-fx-font-weight: normal; -fx-fill: black");
}
String[] result = newValue.substring(firstWord.length()).split("\\s");
int currentIndex = firstWord.length();
for (int i = 0; i < result.length; i++) {
String word = result[i];
if (isValidKeyword(word)) {
_field.setStyle(currentIndex, currentIndex + word.length(),
"-fx-font-weight: bold; -fx-fill: blue");
}
currentIndex += word.length() + 1;
}
} else {
_field.setStyle(0, newValue.length(), "-fx-font-weight: normal; -fx-fill: black");
}
});
}
/**
* Get the first word of the command.
*
* @param newCommand
* - input command
* @return first word
*/
private String getFirstWord(String newCommand) {
String[] textTokens = newCommand.split(" ");
if (textTokens.length > 0) {
return textTokens[0];
}
return null;
}
/**
* Check if the entered word is a valid command.
*
* @param word
* - input word
* @return true if the word is a valid command; false otherwise
*/
private boolean isValidCmd(String word) {
if (CommandType.toCmd(word) != CommandType.INVALID) {
return true;
}
return false;
}
/**
* Check if the entered word is a valid keyword.
*
* @param word
* - input word
* @return true if the word is a valid keyword; false otherwise
*/
private boolean isValidKeyword(String word) {
if (KeywordType.toType(word) != KeywordType.INVALID) {
return true;
}
return false;
}
private void initialiseScene() {
_vbox.getChildren().clear();
_tables.getChildren().clear();
_root.getChildren().clear();
}
private void setCheatSheetContent() throws IOException {
String text;
StringBuilder content = new StringBuilder();
_cheatSheet.setEditable(false);
BorderPane.setMargin(_cheatSheet, new Insets(8, 20, 25, 20));
InputStream is = getClass().getResourceAsStream("cheatsheet.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
while ((text = br.readLine()) != null) {
content.append(text).append("\n");
}
_cheatSheet.clear();
_cheatSheet.appendText(content.toString());
_root.setCenter(_cheatSheet);
br.close();
}
private void exit() {
Platform.exit();
}
}
另外,如果我添加了不必要的标签,我很抱歉。不确定我应该包括什么
p.p.S.我从未让测试文件中的断言完全起作用。如果愿意,您可以忽略它们,因为我现在不想学习如何解决这个问题。您的线程正在从外部源中断(停止),异常被抛出,测试也被中断。抓住它,忽略它
try {
Thread.sleep(7000);
}
catch (InterruptedException e) {}
一个好的测试应该是快速的,并且不依赖于外部事件或类(除了您正在测试的那个)。也许你应该尝试做更小、更有针对性的测试
由于GUI在自己的线程中工作,因此您自己的JUnit测试的结束将杀死它。确保正确关闭GUI。我在中添加了该选项,但它仍然无法工作。发生相同的异常并导致相同的问题(检测到->
[TestFX]用户鼠标移动中的两个字符。中止测试。
,然后线程死亡。该测试也是为该类编写的(我们对此进行了评分),应该是集成测试,所以它测试了所有的类。您使用的是哪个版本?尝试更新到库的最新版本。显然3.1.2中引入了一个bug根据,提供的最新版本是2.3.2(与我的版本相同)。我确实读过关于3.1.2的书,但我不知道如何获得它(或之后的任何版本)。哦,对不起,我指的是testFX的版本。哦,对了,我也有点困惑。嗯,我也不知道如何为testFX下载任何高于3.1.2的版本。不过!!我确实更新了Eclipse中的所有内容(并重新安装了),包括Eclipse本身,它确实神奇地工作了。谢谢你的想法!
package gui;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.runners.MethodSorters;
import org.junit.Test;
import org.loadui.testfx.Assertions;
import org.loadui.testfx.GuiTest;
import org.loadui.testfx.utils.FXTestUtils;
import javafx.scene.Parent;
import javafx.scene.input.KeyCode;
//@@author A0112882H-reused
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class UserInterfaceTest {
private static GuiTest controller;
@BeforeClass
public static void setUpClass() throws InterruptedException {
FXTestUtils.launchApp(UserInterface.class);
Thread.sleep(7000); // Giving the program time to startup. The likely problematic line.
controller = new GuiTest() {
@Override
protected Parent getRootNode() {
return stage.getScene().getRoot();
}
};
System.out.println("GUI TEST START");
}
// @@author A0112882H
@Test
public void test1ShowUndoneEmpty() throws Exception {
UITextField textField = (UITextField) GuiTest.find("#textarea");
controller.click(textField).type("show undone").push(KeyCode.ENTER);
// Assertions.assertNodeExists("");
}
@Test
public void test2AddFloatingTask() throws Exception {
UITextField textField = (UITextField) GuiTest.find("#textarea");
controller.click(textField).type("add Meeting with boss").push(KeyCode.ENTER);
Assertions.assertNodeExists("Meeting with boss");
}
@Test
public void test3Search() throws Exception {
UITextField textField = (UITextField) GuiTest.find("#textarea");
controller.click(textField).type("search Meeting with boss").push(KeyCode.ENTER);
Assertions.assertNodeExists("Meeting with boss");
}
@Test
public void test4ShowUndone() throws Exception {
UITextField textField = (UITextField) GuiTest.find("#textarea");
controller.click(textField).type("show undone").push(KeyCode.ENTER);
Assertions.assertNodeExists("Meeting with boss");
}
@Test
public void test5MarkDone() throws Exception {
UITextField textField = (UITextField) GuiTest.find("#textarea");
controller.click(textField).type("done 1").push(KeyCode.ENTER);
// Assertions.assertNodeExists("Meeting with boss");
}
}
try {
Thread.sleep(7000);
}
catch (InterruptedException e) {}