Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
Test-Driven 
Development with 
JavaFX
About us 
Sven Ruppert Hendrik Ebbers 
@hendrikEbbers 
www.guigarage.com 
@SvenRuppert 
www.rapidpm.org
Content 
• Testing 
• Testing 
• Testing 
Basics 
Frameworks 
CDI
Testing an application 
• unit tests 
how to test an UI component 
• integration tests 
• system tests 
how to test an UI ...
manual testing 
• a tester tests the complete app 
• create a test plan 
• update the test plan for each 
release 
• test ...
CI / CD 
• update the test plan for each commit 
• test each commit 
we don’t want this
UI Test Tools & Libs
IDE based 
Tools like Selenium 
• QF-Test 
• commercial product 
• developer licence costs around 1995 € 
• no JUnit appro...
JemmyFX 
• is for JavaFX 2.2 
• last commit is over 2 years 
ago 
• looks like there is no 
development activity
Automaton 
• is for JavaFX2 
• is developed for Java7 (> u55), is 
running until Java8u11 
• written in Groovy 
• could te...
MarvinFX 
• https://github.com/guigarage/MarvinFX 
• Provides Supervisors for JavaFX Properties
MarvinFX 
define 
PropertySupervisor<String> textSupervisor = 
new PropertySupervisor<>(textfield.textProperty()); 
rules ...
TestFX
TestFX 
• active development 
• LTS branch for Java7 is 
available 
• active branch JavaFX8 only
TestFX 
• verifying the behavior of JavaFX 
applications 
• API for interacting with JavaFX applications. 
• fluent and cl...
TestFX Deep Dive
Let’s start with a small app
Pseudo Code 
click(".text-field").type("steve"); 
click(".password-field").type("duke4ever"); 
click(".button:default"); 
...
step by step 
• Each test must extend the GuiTest class 
public class MyTest extends GuiTest { 
! 
@Test 
public void test...
step by step 
• Provide the root node in your GuiTest 
class 
public class MyTest extends GuiTest { 
! 
protected Parent g...
step by step 
• The GuiTest class provides a lot of 
functions that can be used to interact with 
JavaFX 
@Test 
public vo...
step by step 
• You can use the fluent API 
• You can use CSS selectors to find components 
@Test 
public void testLogin()...
How to interact 
with a specific node?
Extended Node Search 
• TestFX provides additional search methods 
find(„#name-textfield“, find(„#edit-panel“)) 
find the ...
Demo
View Objects Pattern
Any Idea what 
this test does? 
click("#user-field").type("steve"); 
click("#password-field").type("duke4ever"); 
click("#...
View Objects Pattern
View Objects Pattern 
• define a class / object for each view in 
your application 
SearchViewObject AlbumsViewObject 
Tra...
structure 
• Each user interaction is defined as a method 
• The class provides methods to check important 
states 
public...
structure 
• Each method returns the view object for the page 
that is visible after the method has been executed 
• If th...
write readable tests 
@Test 
public void checkTrackCount() { 
new SearchView(this). 
search("Rise Against“). 
openAlbum("T...
Demo
Testing DataFX Flow 
public class Tests extends FlowTest { 
! 
protected Class<?> getFlowStartController() { 
return Searc...
Injection
Problem 
@FlowScoped 
public class ITunesDataModel { 
! 
public void search(String artist) { 
//REST call 
} 
! 
}
extend the class 
@FlowScoped 
public class TestDataModel extends ITunesDataModel 
{ 
! 
public void search(String artist)...
Solution for DataFX 
public class Tests extends FlowTest { 
! 
@Override 
protected void injectTestData(Injector injector)...
Demo
Testing Afterburner.fx 
• apache licensed 
as lean as possible: 3 classes, no 
external dependencies 
• combines: FXML, Co...
Testing Afterburner.fx 
• under active development 
• injection over a few steps is working 
• postconstruct is working 
•...
Testing Afterburner.fx 
• TestFX is working fine with 
afterburner.fx 
• Definition of the tests are the 
same as without ...
Demo Afterburner.fx
TestFX & CDI
Why CDI? 
• Because we want to use 
Mocks 
• Dynamic reconfiguration
Example 
Pa n e 
Controller 
Service
Example 
Pa n e 
Controller 
Service
Example 
Service myService = new Service(); 
@Inject Service myService;
Plain FX Demo
Example 
Pa n e 
Controller 
Mock 
Mock 
Mock 
Service
Example 
Pa n e 
Controller 
Mock 
Mock 
Service
Example 
Pa n e 
Controller 
Mock 
Service
CDI Basic Pattern 
• The production source must 
not contain test sources 
• Therefore we need to 
decouple test & product...
CDI Basic Pattern 
@Inject @MyQualifier 
ServiceInterface myService; 
creates 
@Producer @MyQualifier 
ServiceInterface cr...
CDI Basic Pattern 
@Inject @MyQualifier 
ServiceInterface myService; 
@Producer @MyQualifier 
ServiceInterface createServi...
CDI Basic Pattern 
if(„production“) { 
return service; 
} else { 
return mock; 
}
CDI Basic Pattern 
@Inject @MyQualifier 
ServiceInterface myService; 
@Producer @MyQualifier 
ServiceInterface createServi...
CDI Basic Pattern 
@Inject @MyQualifier 
ServiceInterface myService; 
@Producer @MyQualifier 
ServiceInterface createServi...
CDI Basic Pattern
CDI Basic Pattern
CDI Basic Pattern
CDI Demo
Where to start? 
• www.rapidpm.org 
• github.com/svenruppert/ 
javaone2014
QA
Nächste SlideShare
Wird geladen in …5
×

Test Driven Development with JavaFX

13.687 Aufrufe

Veröffentlicht am

Test Driven Development with JavaFX & TestFX

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

Test Driven Development with JavaFX

  1. 1. Test-Driven Development with JavaFX
  2. 2. About us Sven Ruppert Hendrik Ebbers @hendrikEbbers www.guigarage.com @SvenRuppert www.rapidpm.org
  3. 3. Content • Testing • Testing • Testing Basics Frameworks CDI
  4. 4. Testing an application • unit tests how to test an UI component • integration tests • system tests how to test an UI workflow
  5. 5. manual testing • a tester tests the complete app • create a test plan • update the test plan for each release • test each release
  6. 6. CI / CD • update the test plan for each commit • test each commit we don’t want this
  7. 7. UI Test Tools & Libs
  8. 8. IDE based Tools like Selenium • QF-Test • commercial product • developer licence costs around 1995 € • no JUnit approach • CI integration • nearly the same as froglogic... Oct 2014
  9. 9. JemmyFX • is for JavaFX 2.2 • last commit is over 2 years ago • looks like there is no development activity
  10. 10. Automaton • is for JavaFX2 • is developed for Java7 (> u55), is running until Java8u11 • written in Groovy • could test Swing and JavaFX 2 • recommend TestFX for JavaFX see homepage
  11. 11. MarvinFX • https://github.com/guigarage/MarvinFX • Provides Supervisors for JavaFX Properties
  12. 12. MarvinFX define PropertySupervisor<String> textSupervisor = new PropertySupervisor<>(textfield.textProperty()); rules textPropertySupervisor.assertWillChange(); textPropertySupervisor.assertWillChangeByDefinedCount(3); textPropertySupervisor.assertWillChangeThisWay("A", "B", "C"); interaction //interact with UI by using TestFX check textPropertySupervisor.confirm();
  13. 13. TestFX
  14. 14. TestFX • active development • LTS branch for Java7 is available • active branch JavaFX8 only
  15. 15. TestFX • verifying the behavior of JavaFX applications • API for interacting with JavaFX applications. • fluent and clean API • Supports Hamcrest Matchers and Lambda expressions. • Screenshots of failed tests.
  16. 16. TestFX Deep Dive
  17. 17. Let’s start with a small app
  18. 18. Pseudo Code click(".text-field").type("steve"); click(".password-field").type("duke4ever"); click(".button:default"); assertNodeExists( ".dialog" );
  19. 19. step by step • Each test must extend the GuiTest class public class MyTest extends GuiTest { ! @Test public void testLogin() { . . . } ! }
  20. 20. step by step • Provide the root node in your GuiTest class public class MyTest extends GuiTest { ! protected Parent getRootNode() { . . . } }
  21. 21. step by step • The GuiTest class provides a lot of functions that can be used to interact with JavaFX @Test public void testLogin() { click(„.text-field“); type("steve"); // . . . }
  22. 22. step by step • You can use the fluent API • You can use CSS selectors to find components @Test public void testLogin() { click(„#text-field“).type(„steve“); // . . . }
  23. 23. How to interact with a specific node?
  24. 24. Extended Node Search • TestFX provides additional search methods find(„#name-textfield“, find(„#edit-panel“)) find the textfield in the subpanel
  25. 25. Demo
  26. 26. View Objects Pattern
  27. 27. Any Idea what this test does? click("#user-field").type("steve"); click("#password-field").type("duke4ever"); click("#login-button"); click("#menu-button"); click("#action-35"); click("#tab-5"); click("#next"); click("#next"); click("#next"); click("#details"); assertNodeExists( "#user-picture" );
  28. 28. View Objects Pattern
  29. 29. View Objects Pattern • define a class / object for each view in your application SearchViewObject AlbumsViewObject TracksViewObject PlayViewObject
  30. 30. structure • Each user interaction is defined as a method • The class provides methods to check important states public class AlbumsViewObject { openAlbum(String name) {} checkAlbumCount(int count) {} assertContainsAlbum(String name) {} }
  31. 31. structure • Each method returns the view object for the page that is visible after the method has been executed • If the view won’t change by calling a method the method will return “this“ public TracksViewObject openAlbum(String name) { click((Text t) -> t.getText().contains(name)); return new TracksViewObject(getTestHandler()); } public AlbumsViewObject checkAlbumCount(int count) { assertEquals(count, getList().size()); return this; }
  32. 32. write readable tests @Test public void checkTrackCount() { new SearchView(this). search("Rise Against“). openAlbum("The Black Market“). checkTrackCountOfSelectedAlbum(12); }
  33. 33. Demo
  34. 34. Testing DataFX Flow public class Tests extends FlowTest { ! protected Class<?> getFlowStartController() { return SearchController.class; } ! @Test public void testSearch() { click(„#searchfield“) . . . } }
  35. 35. Injection
  36. 36. Problem @FlowScoped public class ITunesDataModel { ! public void search(String artist) { //REST call } ! }
  37. 37. extend the class @FlowScoped public class TestDataModel extends ITunesDataModel { ! public void search(String artist) { getAlbums().add(. . .); //Adding test data } ! }
  38. 38. Solution for DataFX public class Tests extends FlowTest { ! @Override protected void injectTestData(Injector injector) { injector.inject(new TestDataModel(), ITunesDataModel.class); } ! }
  39. 39. Demo
  40. 40. Testing Afterburner.fx • apache licensed as lean as possible: 3 classes, no external dependencies • combines: FXML, Convention over Configuration and JSR-330 / @Inject • integrated with maven 3
  41. 41. Testing Afterburner.fx • under active development • injection over a few steps is working • postconstruct is working • using existing CDI Services with Annotations (Scopes and so on) is not working with afterburner • no mixed mode with CDI and afterburner.fx
  42. 42. Testing Afterburner.fx • TestFX is working fine with afterburner.fx • Definition of the tests are the same as without afterburner.fx
  43. 43. Demo Afterburner.fx
  44. 44. TestFX & CDI
  45. 45. Why CDI? • Because we want to use Mocks • Dynamic reconfiguration
  46. 46. Example Pa n e Controller Service
  47. 47. Example Pa n e Controller Service
  48. 48. Example Service myService = new Service(); @Inject Service myService;
  49. 49. Plain FX Demo
  50. 50. Example Pa n e Controller Mock Mock Mock Service
  51. 51. Example Pa n e Controller Mock Mock Service
  52. 52. Example Pa n e Controller Mock Service
  53. 53. CDI Basic Pattern • The production source must not contain test sources • Therefore we need to decouple test & production sources physically!
  54. 54. CDI Basic Pattern @Inject @MyQualifier ServiceInterface myService; creates @Producer @MyQualifier ServiceInterface createService(){. . .}
  55. 55. CDI Basic Pattern @Inject @MyQualifier ServiceInterface myService; @Producer @MyQualifier ServiceInterface createService(){. . .} Mock
  56. 56. CDI Basic Pattern if(„production“) { return service; } else { return mock; }
  57. 57. CDI Basic Pattern @Inject @MyQualifier ServiceInterface myService; @Producer @MyQualifier ServiceInterface createService(){. . .} Mock ?
  58. 58. CDI Basic Pattern @Inject @MyQualifier ServiceInterface myService; @Producer @MyQualifier ServiceInterface createService(){. . .} @Producer @Prod ServiceInterface create(){…} Mock @Producer @Mock ServiceInterface create(){…} src/main/java src/test/java
  59. 59. CDI Basic Pattern
  60. 60. CDI Basic Pattern
  61. 61. CDI Basic Pattern
  62. 62. CDI Demo
  63. 63. Where to start? • www.rapidpm.org • github.com/svenruppert/ javaone2014
  64. 64. QA

×