3

我有一个在 maven 下演示 JavaFX + TestFX 的小项目。我用:

  1. Java(TM) SE 运行时环境 (build 1.8.0_40-b26)
  2. 阿帕奇 Maven 3.2.5 (12a6b3acb947671f09b81f49094c53f426d8cea1; 2014-12-14T21:29:23+04:00)

完整来源:https ://github.com/alevohin/testfx-maven-example

我有 2 个无法解决的问题:

1) 当我从 IDE (IDEA) 启动 AppFXTest 时,测试失败

java.lang.ClassNotFoundException: com.sun.glass.ui.monocle.MonoclePlatformFactory
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at com.sun.glass.ui.PlatformFactory.getPlatformFactory(PlatformFactory.java:42)
at com.sun.glass.ui.Application.run(Application.java:146)
at com.sun.javafx.tk.quantum.QuantumToolkit.startup(QuantumToolkit.java:263)
at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:211)
at com.sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.java:675)
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:695)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$152(LauncherImpl.java:182)
at com.sun.javafx.application.LauncherImpl$$Lambda$4/367732825.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Failed to load Glass factory class

如果我禁用 Monocle,它会起作用。但我看到了真正的 JavaFX 窗口和真正的光标单击按钮(“非无头”模式)

2)当我尝试通过 maven 执行测试(evecute mvn clean test)时,我得到另一个错误

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test (default-test) on project testfx-maven-example: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test failed: java.lang.NoClassDefFoundError: javafx/stage/Stage: javafx.stage.Stage -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test (default-test) on project testfx-maven-example: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test failed: java.lang.NoClassDefFoundError: javafx/stage/Stage
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:224)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:355)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:155)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:584)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:216)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:160)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
at org.codehaus.classworlds.Launcher.main(Launcher.java:47)
...
Caused by: java.lang.ClassNotFoundException: javafx.stage.Stage
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.apache.maven.surefire.booter.IsolatedClassLoader.loadClass(IsolatedClassLoader.java:97)
... 48 more

我的 pom.xml 看起来像

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.alevohin</groupId>
    <artifactId>testfx-maven-example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <url>https://github.com/alevohin/javafx-maven-example</url>
    <dependencies>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.9.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testfx</groupId>
            <artifactId>testfx-core</artifactId>
            <version>4.0.1-alpha</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testfx</groupId>
            <artifactId>testfx-junit</artifactId>
            <version>4.0.1-alpha</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.jfxtras</groupId>
            <artifactId>openjfx-monocle</artifactId>
            <version>1.8.0_20</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
                <configuration>
                    <forkCount>1</forkCount>
                    <reuseForks>false</reuseForks>
                    <threadCount>1</threadCount>
                    <systemPropertyVariables>
                        <glass.platform>Monocle</glass.platform>
                        <monocle.platform>Headless</monocle.platform>
                        <prism.order>sw</prism.order>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

AppFXTest

public final class AppFXTest extends ApplicationTest {

    @Override
    public void start(final Stage stage) throws Exception {
        new AppFX().start(stage);
    }

    @Test
    public void showsButtons() throws Exception {
        MatcherAssert.assertThat(
            lookup(".button").queryAll().size(),
            Matchers.is(2)
        );
    }

    @Test
    public void showsBottom() throws Exception {
        final Label label = lookup("BOTTOM").queryFirst();
        MatcherAssert.assertThat(
            label.isVisible(),
            Matchers.is(true)
        );
    }

    @Test
    public void clicksButtons() throws Exception {
        clickOn("A").clickOn("B");
    }
}

应用程序

public final class AppFX extends Application {

    /**
     * Program entry point.
     * @param args Program arguments.
     */
    public static void main(final String... args) {
        Application.launch(AppFX.class, args);
    }

    @Override
    public void start(final Stage stage) throws Exception {
        stage.setTitle("TEST");
        final Scene scene = new Scene(this.centralPane());
        scene.getStylesheets().add(
            AppFX.class.getResource("App.css").toExternalForm()
        );
        stage.setScene(scene);
        stage.setMinWidth(800.0D);
        stage.setMinHeight(600.0D);
        stage.show();
    }

    private Pane centralPane() {
        final BorderPane border = new BorderPane();
        border.setTop(this.buttonsPane());
        border.setCenter(this.centerPane());
        border.setBottom(this.bottomPane());
        return border;
    }

    private Pane buttonsPane() {
        final HBox controls = new HBox();
        controls.setSpacing(5.0D);
        controls.setAlignment(Pos.BASELINE_CENTER);
        controls.getChildren().add(new Label("BUTTONS"));
        controls.getChildren().add(new Button("A"));
        controls.getChildren().add(new Button("B"));
        return controls;
    }

    private Pane centerPane() {
        final VBox pane = new VBox();
        pane.setAlignment(Pos.CENTER);
        pane.getChildren().add(new Label("CENTER"));
        pane.setMinSize(600.0D, 400.0D);
        return pane;
    }

    private Pane bottomPane() {
        final VBox bottom = new VBox();
        final HBox status = new HBox();
        status.setAlignment(Pos.BASELINE_RIGHT);
        bottom.getChildren().add(status);
        status.getChildren().add(new Label("BOTTOM"));
        return bottom;
    }

}

更新

有问题

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test (default-test) on project testfx-maven-example: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test failed: java.lang.NoClassDefFoundError: javafx/stage/Stage: javafx.stage.Stage -> [Help 1]

通过additionalClasspathElements像这样添加到 pom.xml 来解决

 <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
                <configuration>
                    ...
                    <additionalClasspathElements>
                        <additionalClasspathElement>${java.home}/lib/ext/jfxrt.jar</additionalClasspathElement>
                    </additionalClasspathElements>
                </configuration>
            </plugin>
4

3 回答 3

4

Failed to load Glass factory class

我曾经也遇到过这个错误,在我的情况下,我手动构建 Monocle .jar 并将其复制到 JVM (jre/lib/ext)。

根据https://github.com/TestFX/Monocle上的文档构建 Monocle ,或者从 OpenJDK 存储库构建它。

所以以下对我有用:

  • 将您构建的 Monocle .jar 复制到 JDK 的 jre/lib/ext。
  • 使用以下 JVM 参数运行您的应用程序:
-Dtestfx.robot=glass
-Dglass.platform=Monocle
-Dmonocle.platform=Headless
-Dprism.order=sw

-Dtestfx.robot=glass是必要的,因为 TestFX 否则使用 AWTRobot,它使用系统事件队列移动鼠标。也许这足以让您的测试正常工作。

看看你的pom.xml,junit 带来了它自己的版本hamcrest-core,所以你应该排除它以避免问题(如果你想导入几个 hamcrest 匹配器)。我曾经在使用两者时遇到错误。

为了进一步研究,@ItachiUchiha 提供的链接和https://zentrieredich.wordpress.com/2014/12/23/javafx-testen-mit-monocle/上的帖子帮助我使用 Monocle 使用 TestFX。

于 2015-03-18T20:24:02.010 回答
1

我建议使用 TestFX 3.x,因为 4.x 仍然是 alpha 版本。

关于如何测试您的应用程序和 TestFX 的工作的一个非常好的博客在:

TestFX 内部解释

对于单片眼镜的使用,您可以遵循:

使用 TestFX 和 JavaFX 8 进行无头 UI 测试

于 2015-03-18T10:14:43.893 回答
1

摆脱

java.lang.ClassNotFoundException: com.sun.glass.ui.monocle.MonoclePlatformFactory

除了将 Monocle .jar 复制到 JVM (jre/lib/ext))之外,我们还可以将 .jar 添加到我们的项目中,并在运行时将 MonoclePlatformFactory 类加载到类路径中,如下所示:

static {
            try {
                File AGENT_JAR = new File("../lib/openjfx-monocle-1.8.0_20.jar");
                Method addUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
                addUrl.setAccessible(true);
                addUrl.invoke(PlatformFactory.class.getClassLoader(), AGENT_JAR.toURI().toURL());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
于 2018-12-11T12:17:37.093 回答