Skip to content

Provide convenience methods in FXComponentTest to load fxml file #20

@MarceloRuiz

Description

@MarceloRuiz

The three most common scenarios I can think off for using FXComponentTest are:

  • Test a programatically created component (as seen in the FX Test example)

  • Test a component initialized from a FXML file, instantiated with the controller class (if defined in the fxml file, obviously).

  • Test a component initialized from a FXML file, instantiated with a mocked controller.

For the last 2 scenarios, FXComponentTest could easily provide helper methods. The following code could be added to FXComponentTest (and is compatible with issues #17 and #19):

private static final Pattern FXML_CONTROLLER_PATTERN = Pattern.compile("\\sfx:controller=\\\".+\\\"");

protected O loadFromFXML(final String fxmlFileName) throws IOException {
	final URL location = getClass().getResource(fxmlFileName);		
	final FXMLLoader loader = new FXMLLoader(location);
	
	return loader.load();
}

protected O loadFromFXML(final String fxmlFileName, final Object controller) throws IOException, URISyntaxException {	
	final FXMLLoader loader = new FXMLLoader();
	
	loader.setController(controller);
	return loader.load(getControllerStrippedFxml(fxmlFileName));
}	

private InputStream getControllerStrippedFxml(final String fxmlFileName) throws IOException, URISyntaxException {
	final ByteArrayOutputStream fileContent = new ByteArrayOutputStream();
	final StringBuffer strippedContent = new StringBuffer();
	final Matcher matcher;
	
	try (InputStream is = getClass().getResource(fxmlFileName).openStream()) {
		byte[] chunk = new byte[4096];
        	int bytesRead;
        
       		 while ((bytesRead = is.read(chunk)) > 0) {
        		fileContent.write(chunk, 0, bytesRead);
	        }
	}

	matcher = FXML_CONTROLLER_PATTERN.matcher(fileContent.toString());

	while (matcher.find()) {
		matcher.appendReplacement(strippedContent, "");
	}
	matcher.appendTail(strippedContent);
	return new ByteArrayInputStream(strippedContent.toString().getBytes());
}

The above code would allow a user of FXComponentTest create a component just just a few lines of code. For example, suppose I want to test a Pane defined by a fxml file inserted into a BorderPane:

@RunWith(FXRunner.class)
public class MyViewTest extends FXComponentTest<BorderPane, Pane> {

        //other methods here

	@Override
	protected Pane createComponent(final BorderPane parent)  throws IOException {
		final Pane pane = loadFromFXML("myView.fxml");
		
		parent.setCenter(pane);
		return pane;
	}
}

If I want to test the view with a custom controller (mock/stub/spy) then the class would look like:

@RunWith(FXRunner.class)
public class MyViewTest extends FXComponentTest<BorderPane, Pane> {

        final MyController controller = //controller creation here

        //other methods here

	@Override
	protected Pane createComponent(final BorderPane parent)  throws IOException, , URISyntaxException {
		final Pane pane = loadFromFXML("myView.fxml", controller);
		
		parent.setCenter(pane);
		return pane;
	}
}

The added benefit of easily creating a component with a custom controller is that test would be really easy if the user decides to use the PMVC pattern for designing the views.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions