1

パラメータとして JavaFX 要素、たとえばProgressIndicator.

しかしnew ProgressIndicator()、テストメソッドで a を作成すると、(Gradle を使用して) テストを実行すると、その行で a で失敗します

ExceptionInInitializerError 
(...) 
Caused by: java.lang.IllegalStateException: Toolkit not initialized

質問: ローカルと Travis の両方のテストで JavaFX 要素をインスタンス化するにはどうすればよいですか?

ProgressIndicator を使用しないテストが成功することを確認しました。

関連情報

  • Toolkit が初期化されていない Java FXは、FX Toolkit が launch() で開始する前に FX コントロールを作成しようとするとこのエラーが生成されることを明確にしていますが、それから解決策を見つけることができませんでした。テストから launch() を呼び出す必要がありますか?
  • JavaFX 2.1: 初期化されていない Toolkitにエラーが含まれているようですが、CI のテストに関するものではありません。1 つの解決策には が含まれ、CountDownLatchもう 1 つの解決策には同様にテストへの追加が含まcom.sun.javafx.application.PlatformImpl.startup(()->{});れますが、これは問題をローカルで解決するだけで、 が生成されjava.lang.UnsupportedOperationExceptionます。

私のテスト:

import javafx.scene.control.ProgressIndicator;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Tests {@link HelloJavaFX} class.
 */
class HelloJavaFXTest {

    /**
     * Test passes.
     */
    @Test
    public void testCalculate(){
        HelloJavaFX helloJavaFX = new HelloJavaFX();

        assertEquals(2, helloJavaFX.calculate(), "message");
    }

    /**
     * Fails on `new ProgressIndicator();` line.
     */
    @Test
    public void testProgress() {
        HelloJavaFX helloJavaFX = new HelloJavaFX();
        ProgressIndicator progressIndicator = new ProgressIndicator();

        assertTrue(helloJavaFX.setLoading(progressIndicator));
    }

}

私の JavaFX クラス:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Spinner;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * Sample class to show JavaFX.
 */
public class HelloJavaFX extends Application {
    /** height */
    public final int height = 250;
    /** width */
    public final int width = 300;

    /**
     * Main method.
     * @param args Default
     */
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Hello World!");
        Button btn = new Button();
        btn.setText("Say 1+1");
        btn.setOnAction(event -> System.out.println(calculate()));

        Spinner spinner = new Spinner();

        StackPane root = new StackPane();
        root.getChildren().add(btn);
        root.getChildren().add(spinner);
        primaryStage.setScene(new Scene(root, width, height));
        primaryStage.show();
    }

    /**
     * Show 1+1.
     * @return 1+1
     */
    public int calculate() {
        return 1+1;
    }

    /**
     * Indicate something is loading.
     *
     * @param progressIndicator User wants feedback.
     *
     * @return Whether the progress was succesfully set.
     */
    public boolean setLoading(ProgressIndicator progressIndicator) {
        progressIndicator.setVisible(true);
        return true;
    }

}

関連するかどうかはわかりませんが、ビルドファイルでGradleを使用しています:

plugins {
    id 'java'
}

description = """ 
Gradle build file.
This uses the gradle wrapper, so when running (the first time) use 'gradlew test' so then it 
downloads the right gradle automatically.
"""

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.0.3'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.0.3'
}

sourceSets {
    main.java.srcDirs += 'src'
    main.resources.srcDirs += 'src'
    test.java.srcDirs += 'test'
    test.resources.srcDirs += 'test'
}

// Java target version
sourceCompatibility = 1.8

test {
    // Enable JUnit 5 (Gradle 4.6+).
    useJUnitPlatform()

    // Always run tests, even when nothing changed.
    dependsOn 'cleanTest'

    // Show test results.
    testLogging {
        events "passed", "skipped", "failed"
    }
}

スタックトレース:

java.lang.ExceptionInInitializerError
    at deltadak.HelloJavaFXTest.testProgress(HelloJavaFXTest.java:26)
    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:498)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:389)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:167)
    at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:163)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:110)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$3(HierarchicalTestExecutor.java:83)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$null$2(HierarchicalTestExecutor.java:92)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
    at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
    at java.util.Iterator.forEachRemaining(Iterator.java:116)
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$3(HierarchicalTestExecutor.java:92)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$null$2(HierarchicalTestExecutor.java:92)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
    at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
    at java.util.Iterator.forEachRemaining(Iterator.java:116)
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
    at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$3(HierarchicalTestExecutor.java:92)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:51)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:94)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$100(JUnitPlatformTestClassProcessor.java:80)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:71)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    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:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy1.stop(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:123)
    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:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:146)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:128)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: Toolkit not initialized
    at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
    at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
    at com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:550)
    at com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:512)
    at javafx.scene.control.Control.<clinit>(Control.java:87)

完全なサンプル リポジトリはこちらです。

4

1 に答える 1

0

何が起こったか教えてよ。

ご覧のとおり、Travis はすべての JavaFX 要素にアクセスできるわけではないため、JavaFX を起動するだけではローカルでしか機能しません。

TestFXなどの特別な JavaFX テスト ライブラリを使用する必要があります。彼らのwikiには「はじめに」があり、さらに多くのことを行うことができ、ユーザーの操作をシミュレートすることさえできます。

解決策を教えてください!

Junit 5 で使用するにdependenciesは、gradle ビルドのブロックに追加します。

testCompile "org.testfx:testfx-core:4.0.12-alpha"
testCompile "org.testfx:testfx-junit:4.0.12-alpha"

テストに関しては、本当に単純なケースでは、置き換えるだけで十分です

class HelloJavaFXTest {

class HelloJavaFXTest extends FxRobot {

そして交換

public void testProgress() {

public void testProgress() throws TimeoutException {
    // Setup JavaFX for testing.
    FxToolkit.registerPrimaryStage();
    FxToolkit.setupApplication(HelloJavaFX.class);

あなたのメインクラスはどこにあるHelloJavaFXべきですか:拡張するものApplicationです。ただし、更新する必要があります。.travis.ymlそうしないと、UnsupportedOperationException. 彼らのwikiから再び適応:

language: java

jdk: openjdk8

services:
  - xvfb    

before_install:
  - sudo apt update
  - sudo apt install openjfx
  - chmod +x ./gradlew
  - export DISPLAY=:99.0

install: true

script:
  - ./gradlew check

before_cache:
  - rm -f  $HOME/.gradle/caches/modules-2/modules-2.lock
  - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
  - rm -f  $HOME/.gradle/caches/*/fileHashes/fileHashes.bin
  - rm -f  $HOME/.gradle/caches/*/fileHashes/fileHashes.lock

cache:
  directories:
    - $HOME/.gradle/caches/
    - $HOME/.gradle/wrapper/

コトリン!

たとえば、Spek フレームワークを使用する場合など、Kotlin からこれを使用することもできます。ティーザー:

object HelloJavaFXTest: Spek({
    given("the JavaFX Toolkit") {
        // Initialise JavaFX Toolkit, needed for things like ProgressIndicator.
        FxToolkit.registerPrimaryStage()
        FxToolkit.setupApplication(HelloJavaFX::class.java)

        on("instantiating a JavaFX component") {
            val progress = ProgressIndicator()
            it("should not throw any errors") {
                progress.isVisible = false
            }
        }

    }
})

完全なサンプル プロジェクトはこちらです。

于 2018-03-05T17:58:11.450 に答える