-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(testing): Add main section and subsections for controllers and s…
…etup
- Loading branch information
Showing
4 changed files
with
144 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Setup | ||
|
||
In order to properly test your application, it is recommended to use [TestFX](https://github.com/TestFX/TestFX) alongside [Mockito](https://github.com/mockito/mockito). | ||
For a full explanation of both libraries, checkout their official documentation, as the following documentation will only cover a small part of what the projects have to offer. | ||
## TestFX | ||
|
||
TestFX can be used to test the frontend of your application by checking if certain requirements are met, for example view elements being visible or having a certain property. | ||
|
||
Alongside TestFX, we also include Monocle which allows for headless testing without the app having to be open on your screen every time the tests are ran. | ||
|
||
```groovy | ||
testImplementation group: 'org.testfx', name: 'testfx-junit5', version: testFxVersion | ||
testImplementation group: 'org.testfx', name: 'openjfx-monocle', version: monocleVersion | ||
``` | ||
|
||
To enable headless testing, the following lines can be added to your `test` gradle task: | ||
|
||
```groovy | ||
test { | ||
// ... | ||
if (hasProperty('headless') || System.getenv('CI')) { | ||
systemProperties = [ | ||
'java.awt.headless': 'true', | ||
'testfx.robot' : 'glass', | ||
'testfx.headless' : 'true', | ||
'glass.platform' : 'Monocle', | ||
'monocle.platform' : 'Headless', | ||
'prism.order' : 'sw', | ||
'prism.text' : 't2k', | ||
] | ||
} | ||
} | ||
``` | ||
|
||
Whenever the tests are ran with `CI=true`, headless mode will be enabled allowing for testing in CI environments like GH Actions. | ||
|
||
## Mockito | ||
|
||
Mockito is used to redefine certain methods in the code which currently aren't being tested but could influence the test results, for example by accessing an external API. | ||
|
||
```groovy | ||
testImplementation group: 'org.mockito', name: 'mockito-junit-jupiter', version: mockitoVersion | ||
``` | ||
|
||
--- | ||
|
||
[Overview](README.md) | [Testing Controllers ➡](2-controllers) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# Testing Controllers | ||
|
||
In the following section, you will learn how to test a basic controller using TestFX and Mockito. | ||
|
||
## ControllerTest | ||
|
||
Testing controllers using TestFX requires the test to extend from `ApplicationTest`. | ||
It is however recommended to create a helper class called something like `ControllerTest` extending `ApplicationTest` instead of extending it directly. | ||
This class will contain some common code to reduce the amount of boilerplate required for each controller test. | ||
|
||
```java | ||
public class ControllerTest extends ApplicationTest { | ||
|
||
@Spy | ||
public final App app = new App(); | ||
@Spy | ||
protected final ResourceBundle resources = ...; // Define common instances here and mock/spy them | ||
|
||
protected Stage stage; // Useful for checking the title for example | ||
|
||
@Override | ||
public void start(Stage stage) throws Exception { | ||
super.start(stage); | ||
this.stage = stage; | ||
app.start(stage); | ||
stage.requestFocus(); // Make the test use the correct stage | ||
} | ||
} | ||
``` | ||
|
||
The main annotations offered by Mockito are `@Spy` and `@Mock`. | ||
Mocking an instance completely removes all default behaviour and content of methods, fields and such, resulting in an empty shell which can later be redefined. | ||
This is useful if the real behaviour isn't needed at all, but the instance itself has to exist. | ||
Spying an instance doesn't touch the default behaviour but allows redefining parts of the logic. | ||
|
||
Spies and Mocks can later be injected into the controller instance which is being tested using `@InjectMocks`. | ||
|
||
## Writing a real test | ||
|
||
Since most of the setup is already defined in the `ControllerTest` class we can just extend it for our own tests. | ||
|
||
```java | ||
@ExtendWith(MockitoExtension.class) | ||
public class SetupControllerTest extends ControllerTest { | ||
|
||
@InjectMocks | ||
SetupController setupController; | ||
|
||
@Override | ||
public void start(Stage stage) throws Exception { | ||
super.start(stage); // It is important to call super.start(stage) to setup the test correctly | ||
app.show(setupController); | ||
} | ||
|
||
@Test | ||
public void test() { | ||
// Since we don't really want to show a different controller, we mock the show() method's behaviour to just return a vbox | ||
doReturn(new VBox()).when(app).show(any(), any()); | ||
|
||
assertEquals("Ludo - Set up the game", app.stage().getTitle()); | ||
|
||
// TestFX offers different methods for interacting with the application | ||
moveTo("2"); | ||
moveBy(0, -20); | ||
press(MouseButton.PRIMARY); | ||
release(MouseButton.PRIMARY); | ||
clickOn("#startButton"); | ||
|
||
// Mockito can be used to check if the show() method was called with certain arguments | ||
verify(app, times(1)).show("ingame", Map.of("playerAmount", 2)); | ||
|
||
} | ||
|
||
} | ||
``` | ||
|
||
Whenever something is loading asynchronously the method `waitForFxEvents()` should be called before checking the results. | ||
This assures that all JavaFX events have been run before continuing the tests. | ||
Another way of waiting is the `sleep()` method, which allows to wait for a predefined time. | ||
|
||
--- | ||
|
||
[⬅ Setup](1-setup.md) | [Overview](README.md) | [Testing SubComponents ➡](2-subcomponents.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Testing | ||
|
||
There are plenty of ways to test different parts of your application. | ||
This section covers the testing of controllers including view tests using TestFX and mocking using Mockito. | ||
Since fulibFx uses Dagger internally and for example applications, the last subsection also contains some hints for working with dagger in tests. | ||
|
||
1. [Setup](1-setup.md) | ||
2. [Testing Controllers](2-controllers.md) | ||
3. [Testing SubComponents](3-subcomponents.md) | ||
4. [Testing with Dagger](4-dagger.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters