如何在Spring Boot测试中设置'无头'属性?

问题描述:

我正在使用Spring Boot和JavaFX进行测试(基于解释这个的some excellent YouTube videos)。如何在Spring Boot测试中设置'无头'属性?

,使其与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,因为这个'headless'属性没有像正常启动时那样设置为false。如何在测试期间设置此属性?

编辑:

更仔细地观察,似乎有2个方面开始,一个春节测试框架开始和一个我在init方法手动创建,所以测试的应用程序未使用嘲笑豆。如果有人想知道如何获得init()方法中的测试环境参考,我会非常高兴。

+1

可能是[link](http://*.com/questions/36160353/why-does-swing-think-its-headless-under-spring-boot-but-not-under-spring-or- pl)会帮助你。 –

Praveen Kumar的评论指出了良好的方向。当我用-Djava.awt.headless=false运行测试时,则没有例外。

为了解决2个春天上下文的其他问题,我必须做到以下几点:

想这是你的主了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; 
    } 
} 

并进行测试,使用这种抽象基类(Courtesy of this YouTube video by MVP Java):

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。