6

JavaFX で Spring Boot を使用してテストしています (これを説明するいくつかの優れた YouTube ビデオに基づいています)。

TestFXで動作させるには、次のようなコンテキストを作成する必要があります。

@Override
public void init() throws Exception {
    SpringApplicationBuilder builder = new SpringApplicationBuilder(MyJavaFXApplication.class);
    builder.headless(false); // Needed for TestFX
    context = builder.run(getParameters().getRaw().stream().toArray(String[]::new));

    FXMLLoader loader = new FXMLLoader(getClass().getResource("main.fxml"));
    loader.setControllerFactory(context::getBean);
    rootNode = loader.load();
}

私は今、この JavaFX アプリケーションをテストしたいと思っています。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class MyJavaFXApplicationUITest extends TestFXBase {

    @MockBean
    private MachineService machineService;

    @Test
    public void test() throws InterruptedException {
        WaitForAsyncUtils.waitForFxEvents();
        verifyThat("#statusText", (Text text ) -> text.getText().equals("Machine stopped"));
        clickOn("#startMachineButton");
        verifyThat("#startMachineButton", Node::isDisabled);
        verifyThat("#statusText", (Text text ) -> text.getText().equals("Machine started"));
    }
}

これにより、Spring コンテキストが開始され、期待どおりに「通常の」Bean がモック Bean に置き換えられます。

ただし、java.awt.HeadlessException通常の起動時に行われるように、この「ヘッドレス」プロパティが false に設定されていないため、 が表示されます。テスト中にこのプロパティを設定するにはどうすればよいですか?

編集:

よく見ると、Spring テスト フレームワークが開始するコンテキストと、initメソッドで手動で作成するコンテキストの 2 つのコンテキストが開始されているように見えるため、テスト対象のアプリケーションはモック Bean を使用していません。メソッドでテスト コンテキストの参照を取得する方法を誰かが知っていれば、init()とてもうれしいです。

4

2 に答える 2

4

Praveen Kumar からのコメントは、良い方向を示しています。でテストを実行すると-Djava.awt.headless=false、例外はありません。

2 つの Spring コンテキストの他の問題を解決するには、次のことを行う必要がありました。

これがメインの JavaFx スタートアップ クラスであるとします。

    @SpringBootApplication
    public class MyJavaFXClientApplication extends Application {

    private ConfigurableApplicationContext context;
    private Parent rootNode;

    @Override
    public void init() throws Exception {
        SpringApplicationBuilder builder = new SpringApplicationBuilder(MyJavaFXClientApplication.class);
        builder.headless(false); // Needed for TestFX
        context = builder.run(getParameters().getRaw().stream().toArray(String[]::new));

        FXMLLoader loader = new FXMLLoader(getClass().getResource("main.fxml"));
        loader.setControllerFactory(context::getBean);
        rootNode = loader.load();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
        double width = visualBounds.getWidth();
        double height = visualBounds.getHeight();

        primaryStage.setScene(new Scene(rootNode, width, height));
        primaryStage.centerOnScreen();
        primaryStage.show();
    }

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void stop() throws Exception {
        context.close();
    }

    public void setContext(ConfigurableApplicationContext context) {
        this.context = context;
    }
}

そして、テストのために、この抽象基本クラスを使用します ( MVP Javaによるこの YouTube ビデオの礼儀):

public abstract class TestFXBase extends ApplicationTest {

    @BeforeClass
    public static void setupHeadlessMode() {
        if (Boolean.getBoolean("headless")) {
            System.setProperty("testfx.robot", "glass");
            System.setProperty("testfx.headless", "true");
            System.setProperty("prism.order", "sw");
            System.setProperty("prism.text", "t2k");
            System.setProperty("java.awt.headless", "true");
        }
    }

    @After
    public void afterEachTest() throws TimeoutException {
        FxToolkit.hideStage();
        release(new KeyCode[0]);
        release(new MouseButton[0]);
    }

    @SuppressWarnings("unchecked")
    public <T extends Node> T find(String query, Class<T> clazz) {
        return (T) lookup(query).queryAll().iterator().next();
    }
}

次に、次のようなテストを記述できます。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class MyJavaFXApplicationUITest extends TestFXBase {

    @MockBean
    private TemperatureService temperatureService;

    @Autowired
    private ConfigurableApplicationContext context;

    @Override
    public void start(Stage stage) throws Exception {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("main.fxml"));
        loader.setControllerFactory(context::getBean);
        Parent rootNode = loader.load();

        stage.setScene(new Scene(rootNode, 800, 600));
        stage.centerOnScreen();
        stage.show();
    }

    @Test
    public void testTemperatureReading() throws InterruptedException {
        when(temperatureService.getCurrentTemperature()).thenReturn(new Temperature(25.0));
        WaitForAsyncUtils.waitForFxEvents();

        assertThat(find("#temperatureText", Text.class).getText()).isEqualTo("25.00 C");
    }
}

これにより、モック サービスを使用して UI を開始できます。

于 2016-09-01T08:48:08.423 に答える