Простой пример TestFX не удается

Работая с TestFX 4.0.14 в Eclipse Photon и fx9 или fx11 (не имеет значения), простой пример теста из вики TestFX дает сбой в should_click_on_button() с

Expected: Labeled has text "clicked!"
         but: was "click me!"

При взгляде на экран отображается панель и содержащаяся в ней кнопка, но мышь перемещается в другое место, поэтому кнопка никогда не нажимается и, следовательно, ее текст никогда не изменяется.

Есть идеи, что не так / как исправить?

Тестовый код (все для удобства скопировано из вики):

import org.junit.Test;
import org.testfx.framework.junit.ApplicationTest;

import static org.testfx.api.FxAssert.*;
import static org.testfx.matcher.control.LabeledMatchers.*;

import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 * Simple testfx example from testfx wiki:
 * https://github.com/TestFX/TestFX/wiki/Getting-Started
 * 
 */
public class ClickApplicationTest extends ApplicationTest {
    @Override
    public void start(Stage stage) {
        Parent sceneRoot = new ClickApplication.ClickPane();
        Scene scene = new Scene(sceneRoot, 100, 100);
        stage.setScene(scene);
        stage.show();
    }

    @Test
    public void should_contain_button() {
        // expect:
        verifyThat(".button", hasText("click me!"));
    }

    @Test
    public void should_click_on_button() {
        // when:
        clickOn(".button");

        // then:
        verifyThat(".button", hasText("clicked!"));
    }


}

Код приложения:

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

/**
 * Simple testfx example from testfx wiki:
 * https://github.com/TestFX/TestFX/wiki/Getting-Started
 * 
 */
public class ClickApplication extends Application {
    // application for acceptance tests.
    @Override public void start(Stage stage) {
        Parent sceneRoot = new ClickPane();
        Scene scene = new Scene(sceneRoot, 100, 100);
        stage.setScene(scene);
        stage.show();
    }

    // scene object for unit tests
    public static class ClickPane extends StackPane {
        public ClickPane() {
            super();
            Button button = new Button("click me!");
            button.setOnAction(actionEvent -> button.setText("clicked!"));
            getChildren().add(button);
        }
    }
}

Обновить:

Найдена открытая проблема в TestFX, которая может совпадать. В нем упоминается основная ошибка fx, которая может быть причиной - но, похоже, ее нет: она исправлена ​​в fx11 (проверено, что код в отчете об основной ошибке проходит), но проблема testfx преобладает..

2 ответа

Решение

Оказалось, проблема с несколькими причинами:

  • в основе лежит основная ошибка - робот не работает правильно на win (только 10?) экранах HiDPI, поэтому не все испытывают сбои
  • ошибка в ядре исправлена ​​в fx11 (в собственном коде win), так что теперь общедоступный робот fx ведет себя хорошо
  • Код, связанный с роботом TestFX в последней версии (4.0.14), еще не обновлен до fx11, версия репо
  • по умолчанию TestFX использует AWTRobot, который все еще не работает (по крайней мере, в контексте TestFX, пример в отчете об основной ошибке проходит)
  • чтобы тесты TestFX работали надежно на экранах Win HiDPI, нам нужно принудительно использовать робот fx, установив системное свойство testfx.robot на glass
  • Последнее замечание: при установке свойства программно через System.getProperties().put("testfx.robot", "glass") в тестовом коде это необходимо сделать до запуска тестового класса, то есть в методе, аннотированном @BeforeClass (не в @Before или testApp.init())! В противном случае самый первый тест, в котором прямо или косвенно задействуется mouseMove, будет неудачным, последующие из них будут хорошими (какое-то время я озадачен, потому что неудача кажется ложной;).

Образец:

public class ClickTest extends ApplicationTest {

    @Test
    public void testClick() {
        verifyThat(".button", hasText("click me!"));
        clickOn(".button");
        verifyThat(".button", hasText("clicked!"));
    }

    /**
     * Use glass robot.
     * Note: this must happen once before the class is loaded. Otherwise,
     * the very first test run uses the awt robot
     */
    @BeforeClass
    public static void config() throws Exception {
        System.getProperties().put("testfx.robot", "glass");
    }

    @Override
    public void start(Stage stage) {
        Parent sceneRoot = new ClickPane();
        Scene scene = new Scene(sceneRoot, 100, 100);
        stage.setScene(scene);
        stage.show();
    }

    // scene object for unit tests
    public static class ClickPane extends StackPane {
        public ClickPane() {
            super();
            Button button = new Button("click me!");
            button.setOnAction(actionEvent -> button.setText("clicked!"));
            getChildren().add(button);
        }
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(ClickTest.class.getName());
}

Меня устраивает.

В любом случае, вы можете проверять изменение пользовательского интерфейса до того, как оно произойдет, поскольку оно выполняется в потоке приложения FX, а не в потоке, выполняющем тест.

Используйте эту строку

WaitForAsyncUtils.waitForFxEvents()

между clickOn а также verifyThat звонки.

Другие вопросы по тегам