April 13-16, 2011. Oxford, UK                          Writing web UI in                         Testfirst fashion with    ...
About me      Uberto Barbini      Software artisan      Agile enthusiast.      Hobby:      photography and the game of Go....
Editorial platform for big company:                                  4-5 people team                             agile (sc...
http://netnumero.comSunday, April 17, 2011
http://netnumero.com                                 NetNumero numbers:                          5 people on weekends and ...
Four Noble Truths                         of BuddhismSunday, April 17, 2011
Four Noble Truths                                      of Buddhism                     • Suffering exists                 ...
Four Noble Truths                         of complex* web applications development                                        ...
Four Noble Truths                          of complex* web applications development                     • Suffering exists...
What’s GWT                          anyway?Sunday, April 17, 2011
What’s GWT                           anyway?                                Short version:                         Java to...
Where to start    Be s t                         bo ok           Be s t      Gwt and        s tart                   to   ...
GWT magic 1                                      The compiler                   •     Directories will be created containi...
GWT magic 1                                      The compiler                   •     Directories will be created containi...
GWT magic 1                                      The compiler                   •     Directories will be created containi...
NetNumero compilation:                          Compiling 10 permutations                               Compiling permutat...
NetNumero compilation:                                                              5 Browsers x 2                        ...
NetNumero compilation:                                                              5 Browsers x 2                        ...
After running the GWT compiler your war directory                 should look something like this:                 C:gwt-2...
Your 5 permutations                                                               of compiled JS                 After run...
Your 5 permutations                                                                of compiled JS                 After ru...
GWT magic 2                         Development mode           Devmode main advantage is client code hot-replace.         ...
GWT magic 3                         RPC servicesSunday, April 17, 2011
GWT magic 3                         RPC services                         1Sunday, April 17, 2011
GWT magic 3                         RPC services                         1      2Sunday, April 17, 2011
GWT magic 3                         RPC services                         1      2       3Sunday, April 17, 2011
Enough talk, let’s code!Sunday, April 17, 2011
• example of Hello in devmode                     • example in IntelliJ of BugList HelloSunday, April 17, 2011
Example HelloWorld                                     Starting with the                                     gwt helloworl...
package com.mySampleApplication.client;                                                                       private stat...
package com.mySampleApplication.client;                        public void testNotifyServerError() throws Exception       ...
package com.mySampleApplication.client;                        public void testNotifyServerError() throws Exception       ...
package com.mySampleApplication.client;                        public void testNotifyServerError() throws Exception       ...
package com.mySampleApplication.client;                        public void testNotifyServerError() throws Exception       ...
package com.mySampleApplication.client;                        public void testNotifyServerError() throws Exception       ...
package com.mySampleApplication.client;                        public void testNotifyServerError() throws Exception       ...
HelloWorld with Tests                         What we learned?Sunday, April 17, 2011
HelloWorld with Tests                         What we learned?                         Gwt HelloWorld can easily be tested...
HelloWorld with Tests                         What we learned?                         Gwt HelloWorld can easily be tested...
HelloWorld with Tests                         What we learned?                         Gwt HelloWorld can easily be tested...
Ok, now I know                      I can test all my                      Gwt classes...                            But l...
Introducing MVP           Remove Presenter and View from ApplicationSunday, April 17, 2011
Introducing MVP           Remove Presenter and View from ApplicationSunday, April 17, 2011
Introducing MVP           Remove Presenter and View from Application                                   ApplicationSunday, ...
Introducing MVP           Remove Presenter and View from Application                                   ApplicationSunday, ...
Introducing MVP           Remove Presenter and View from Application                                      Application     ...
Introducing MVP           Remove Presenter and View from Application                                      Application     ...
Introducing MVP           Remove Presenter and View from Application                                      Application     ...
Introducing MVP           Remove Presenter and View from Application                                      Application     ...
Introducing MVP           Remove Presenter and View from Application                                      Application     ...
public class MySampleApplication implements                                     }       EntryPoint {                      ...
public class BugListViewFlexTable extends ViewAbstractRoot implements BugListView {             public Button clickMeButto...
ublic class BugListViewTest extends GwtTestWithApp {             private BugListView bugListView;             @Override   ...
public class BugListPresenterTest {                                                                @Test       @Before    ...
public class BugListPresenterTest {       @Before                                             Presenter with              ...
MVP Unit Tests                                   Client GWT Tests                                      Pure Java          ...
Model View PresenterSunday, April 17, 2011
Model View Presenter                     • 100% test coverage.                         To let them drive your design.Sunda...
Model View Presenter                     • 100% test coverage.                         To let them drive your design.     ...
Model View Presenter                     • 100% test coverage.                         To let them drive your design.     ...
Model View Presenter                     • 100% test coverage.                         To let them drive your design.     ...
Model View Presenter                     • 100% test coverage.                         To let them drive your design.     ...
If you have to remember just a                         Model View Presenter                     slide please remember this...
Example BugTrackerSunday, April 17, 2011
Example BugTracker                     • First theTDD                       serverside                                  Mo...
Example BugTracker                     • First theTDD                       serverside                                  Mo...
Example BugTracker                     • First theTDD                       serverside                                  Mo...
Example BugTracker                     • First theTDD                       serverside                                  Mo...
NetNumero.comSunday, April 17, 2011
NetNumero.com                     • We started in TDD only on the serverSunday, April 17, 2011
NetNumero.com                     • We started in TDD only on the server                     • Then we refactored to GOOS ...
NetNumero.com                     • We started in TDD only on the server                     • Then we refactored to GOOS ...
NetNumero.com                     • We started in TDD only on the server                     • Then we refactored to GOOS ...
NetNumero.com                     • We started in TDD only on the server                     • Then we refactored to GOOS ...
Browser - JavaScript       Dual-Exagon              Events       Architecture      User                                   ...
Browser - JavaScript       Dual-Exagon                                     Events       Architecture                      ...
Browser - JavaScript       Dual-Exagon                                     Events       Architecture                      ...
Browser - JavaScript       Dual-Exagon                                     Events       Architecture                      ...
Client                         Browser - JavaScript                                               S                       ...
Client                         Browser - JavaScript         Write your own                                               S...
Client                         Browser - JavaScript         Write your own                                               S...
Server                                                     Ajax                                                     Servle...
Server                                                     Ajax   Get the ajax call,                                Servle...
Server                                                     Ajax   Get the ajax call,                                Servle...
When things grow upSunday, April 17, 2011
When things grow up                     • Code splitSunday, April 17, 2011
When things grow up                     • Code split                     • Presenter proxy patternSunday, April 17, 2011
When things grow up                     • Code split                     • Presenter proxy pattern                     • M...
Code split reportSunday, April 17, 2011
Code split report                                 This is your obfuscated total                                       java...
Code split report                                 This is your obfuscated total                                       java...
Code split report                                 This is your obfuscated total                                       java...
Split codeSunday, April 17, 2011
• examples:Sunday, April 17, 2011
Sparse thoughts                     • It’s not that I don’t like JS. It’s all about tools                         and havi...
The future...Sunday, April 17, 2011
The future...Sunday, April 17, 2011
The future...                     my wish list:Sunday, April 17, 2011
The future...                     my wish list:                     •Incremental compileSunday, April 17, 2011
The future...                     my wish list:                     •Incremental compile                     •Multi browse...
The future...                     my wish list:                     •Incremental compile                     •Multi browse...
The future...                     my wish list:                     •Incremental compile                     •Multi browse...
Upcoming SlideShare
Loading in...5
×

Develop Gwt application in TDD

3,501

Published on

Talk at ACCU2011 Conference.
http://accu.org/index.php/conferences/accu_conference_2011/accu2011_sessions

Gwt offer you an easy and agile way to create your complex ajax application in a tdd fashion. The slides shows also some real code on how to accomplish this.

Published in: Technology
3 Comments
7 Likes
Statistics
Notes
No Downloads
Views
Total Views
3,501
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
109
Comments
3
Likes
7
Embeds 0
No embeds

No notes for slide

Develop Gwt application in TDD

  1. 1. April 13-16, 2011. Oxford, UK Writing web UI in Testfirst fashion with GWT Uberto Barbini uberto@ubiland.net twitter: @ramtopSunday, April 17, 2011
  2. 2. About me Uberto Barbini Software artisan Agile enthusiast. Hobby: photography and the game of Go. Teamleader and Architect for Vodafone editorial and backend products.Sunday, April 17, 2011
  3. 3. Editorial platform for big company: 4-5 people team agile (scrum and kanban) gwt, hibernate, smartgwt started jan 2009 version 1.0 june 2009, now 3.2 total lines of code: ~2.000.000 test coverage: ~60%Sunday, April 17, 2011
  4. 4. http://netnumero.comSunday, April 17, 2011
  5. 5. http://netnumero.com NetNumero numbers: 5 people on weekends and nights 1 year with many pauses Test coverage: Total classes 94.1% (272/ 289) Total methods 73.7% (1004/ 1363) Total lines 79.1% (5125/ 6481)Sunday, April 17, 2011
  6. 6. Four Noble Truths of BuddhismSunday, April 17, 2011
  7. 7. Four Noble Truths of Buddhism • Suffering exists • Suffering arises from attachment to desires • Suffering ceases when attachment to desire ceases • Freedom from suffering is possible by practising the Eightfold PathSunday, April 17, 2011
  8. 8. Four Noble Truths of complex* web applications development Text * If your url can contain all the app state is not a complex application. Just use RestSunday, April 17, 2011
  9. 9. Four Noble Truths of complex* web applications development • Suffering exists when writing complex web application • Suffering arises from user state attachment Text on the server • Suffering ceases when attachment to user status ceases • Freedom from suffering is possible by practicing the GWT Path * If your url can contain all the app state is not a complex application. Just use RestSunday, April 17, 2011
  10. 10. What’s GWT anyway?Sunday, April 17, 2011
  11. 11. What’s GWT anyway? Short version: Java to Javascript compilerSunday, April 17, 2011
  12. 12. Where to start Be s t bo ok Be s t Gwt and s tart to w it h reference Sw ing are Gwt on Gwt similar Many video on Google like: http://www.google.com/events/io/2009/sessions/ GoogleWebToolkitBestPractices.htmlSunday, April 17, 2011
  13. 13. GWT magic 1 The compiler • Directories will be created containing the JavaScript implementation of your project. One directory for each module. C:gwt-2.0.0samplesHello>ant Buildfile: build.xml libs: javac: gwtc: [java] Compiling module com.google.gwt.sample.hello.Hello [java] Compiling 5 permutations [java] Permutation compile succeeded [java] Linking into war [java] Link succeeded [java] Compilation succeeded -- 20.313s build: BUILD SUCCESSFUL Total time: 22 secondsSunday, April 17, 2011
  14. 14. GWT magic 1 The compiler • Directories will be created containing the JavaScript implementation of your project. One directory for each module. C:gwt-2.0.0samplesHello>ant Buildfile: build.xml 5 x supported browser x 1 locale. libs: 6 Browsers in 6 languages = 36 permutations! javac: gwtc: [java] Compiling module com.google.gwt.sample.hello.Hello [java] Compiling 5 permutations [java] Permutation compile succeeded [java] Linking into war [java] Link succeeded [java] Compilation succeeded -- 20.313s build: BUILD SUCCESSFUL Total time: 22 secondsSunday, April 17, 2011
  15. 15. GWT magic 1 The compiler • Directories will be created containing the JavaScript implementation of your project. One directory for each module. C:gwt-2.0.0samplesHello>ant Buildfile: build.xml 5 x supported browser x 1 locale. libs: 6 Browsers in 6 languages = 36 permutations! javac: gwtc: [java] Compiling module com.google.gwt.sample.hello.Hello [java] Compiling 5 permutations [java] Permutation compile succeeded [java] Linking into war [java] Link succeeded [java] Compilation succeeded -- 20.313s build: 22 seconds for an helloworld. BUILD SUCCESSFUL Total time: 22 seconds Several minutes for real projects.Sunday, April 17, 2011
  16. 16. NetNumero compilation: Compiling 10 permutations Compiling permutation 0... Compiling permutation 1... Compiling permutation 2... Compiling permutation 3... Compiling permutation 4... Compiling permutation 5... Compiling permutation 6... Compiling permutation 7... Compiling permutation 8... Compiling permutation 9... Compile of permutations succeeded Linking into /Users/ubertobarbini/svijava/netnumero/ war/application. Writing extras to /Users/ ubertobarbini/svijava/netnumero/extra/application Link succeeded Compilation succeeded -- 354.190sSunday, April 17, 2011
  17. 17. NetNumero compilation: 5 Browsers x 2 Languages Compiling 10 permutations Compiling permutation 0... Compiling permutation 1... Compiling permutation 2... Compiling permutation 3... Compiling permutation 4... Compiling permutation 5... Compiling permutation 6... Compiling permutation 7... Compiling permutation 8... Compiling permutation 9... Compile of permutations succeeded Linking into /Users/ubertobarbini/svijava/netnumero/ war/application. Writing extras to /Users/ ubertobarbini/svijava/netnumero/extra/application Link succeeded Compilation succeeded -- 354.190sSunday, April 17, 2011
  18. 18. NetNumero compilation: 5 Browsers x 2 Languages Compiling 10 permutations Compiling permutation 0... Compiling permutation 1... Compiling permutation 2... Compiling permutation 3... Compiling permutation 4... Compiling permutation 5... Compiling permutation 6... Compiling permutation 7... Compiling permutation 8... Compiling permutation 9... Compile of permutations succeeded Linking into /Users/ubertobarbini/svijava/netnumero/ war/application. Writing extras to /Users/ ubertobarbini/svijava/netnumero/extra/application Link succeeded Compilation succeeded -- 354.190s about 6 minutesSunday, April 17, 2011
  19. 19. After running the GWT compiler your war directory should look something like this: C:gwt-2.0.0samplesHello>binfind war war warhello warhello18EEC2DA45CB5F0C2050E2539AE61FCE.cache.html warhello813B962DC4C22396EA14405DDEF020EE.cache.html warhello86DA1DCEF4F40731BE71E7978CD4776A.cache.html warhelloA37FC20FF4D8F11605B2C4C53AF20B6F.cache.html warhelloE3C1ABB32E39A126A9194DB727F7742A.cache.html warhello14A43CD7E24B0A0136C2B8B20D6DF3C0.cache.png warhello548CDF11D6FE9011F3447CA200D7FB7F.cache.png warhello9DA92932034707C17CFF15F95086D53F.cache.png warhelloA7CD51F9E5A7DED5F85AD1D82BA67A8A.cache.png warhelloB8517E9C2E38AA39AB7C0051564224D3.cache.png warhelloclear.cache.gif warhellohello.nocache.js warhellohosted.html warHello.htmlSunday, April 17, 2011
  20. 20. Your 5 permutations of compiled JS After running the GWT compiler your war directory should look something like this: C:gwt-2.0.0samplesHello>binfind war war warhello warhello18EEC2DA45CB5F0C2050E2539AE61FCE.cache.html warhello813B962DC4C22396EA14405DDEF020EE.cache.html warhello86DA1DCEF4F40731BE71E7978CD4776A.cache.html warhelloA37FC20FF4D8F11605B2C4C53AF20B6F.cache.html warhelloE3C1ABB32E39A126A9194DB727F7742A.cache.html warhello14A43CD7E24B0A0136C2B8B20D6DF3C0.cache.png warhello548CDF11D6FE9011F3447CA200D7FB7F.cache.png warhello9DA92932034707C17CFF15F95086D53F.cache.png warhelloA7CD51F9E5A7DED5F85AD1D82BA67A8A.cache.png warhelloB8517E9C2E38AA39AB7C0051564224D3.cache.png warhelloclear.cache.gif warhellohello.nocache.js warhellohosted.html warHello.htmlSunday, April 17, 2011
  21. 21. Your 5 permutations of compiled JS After running the GWT compiler your war directory should look something like this: C:gwt-2.0.0samplesHello>binfind war war warhello warhello18EEC2DA45CB5F0C2050E2539AE61FCE.cache.html warhello813B962DC4C22396EA14405DDEF020EE.cache.html warhello86DA1DCEF4F40731BE71E7978CD4776A.cache.html warhelloA37FC20FF4D8F11605B2C4C53AF20B6F.cache.html warhelloE3C1ABB32E39A126A9194DB727F7742A.cache.html warhello14A43CD7E24B0A0136C2B8B20D6DF3C0.cache.png warhello548CDF11D6FE9011F3447CA200D7FB7F.cache.png warhello9DA92932034707C17CFF15F95086D53F.cache.png warhelloA7CD51F9E5A7DED5F85AD1D82BA67A8A.cache.png warhelloB8517E9C2E38AA39AB7C0051564224D3.cache.png warhelloclear.cache.gif warhellohello.nocache.js warhellohosted.html This is the non-cachable warHello.html JS launcher (select the permutation).Sunday, April 17, 2011
  22. 22. GWT magic 2 Development mode Devmode main advantage is client code hot-replace. You need just a refresh on the browser.Sunday, April 17, 2011
  23. 23. GWT magic 3 RPC servicesSunday, April 17, 2011
  24. 24. GWT magic 3 RPC services 1Sunday, April 17, 2011
  25. 25. GWT magic 3 RPC services 1 2Sunday, April 17, 2011
  26. 26. GWT magic 3 RPC services 1 2 3Sunday, April 17, 2011
  27. 27. Enough talk, let’s code!Sunday, April 17, 2011
  28. 28. • example of Hello in devmode • example in IntelliJ of BugList HelloSunday, April 17, 2011
  29. 29. Example HelloWorld Starting with the gwt helloworld example we can write test to cover everything. Let’s see how...Sunday, April 17, 2011
  30. 30. package com.mySampleApplication.client; private static class MyAsyncCallback implements import <...> AsyncCallback<String> { private Label label; public class MySampleApplication implements public MyAsyncCallback(Label label) { EntryPoint { this.label = label; } public Button clickMeButton; public Label messageLabel; public void onSuccess(String result) { public String message = "Hello, World!"; label.getElement().setInnerHTML(result); } public void onModuleLoad() { clickMeButton = new Button("Click me"); public void onFailure(Throwable throwable) { messageLabel = new Label(); label.setText("Failed to receive answer from server!"); clickMeButton.addClickHandler } (createClickHandler(messageLabel, message)); } } RootPanel.get("slot1").add(clickMeButton); Application start RootPanel.get("slot2").add(messageLabel); } private ClickHandler createClickHandler(final Label label, final String msg) { return new ClickHandler() { Ajax call on click public void onClick(ClickEvent event) { if (label.getText().equals("")) { MySampleApplicationService.App.getInstance ().getMessage(msg, new MyAsyncCallback(label)); Result of ajax call } else { label.setText(""); on the label } } }; }Sunday, April 17, 2011
  31. 31. package com.mySampleApplication.client; public void testNotifyServerError() throws Exception {import ... final MySampleApplication wrongApp = new MySampleApplication();public class MySampleApplicationTest extends GWTTestCase wrongApp.message = null; //to simulate an error{ from server @Override wrongApp.onModuleLoad(); protected void gwtSetUp() throws Exception { } ...//setup stuff wrongApp.clickMeButton.click(); @Override asyncTestValidation(new Timer() { public String getModuleName() { public void run() {... } // return .gwt.xml name assertEquals("Failed to receive answer from server!", wrongApp.messageLabel.getText()); private void asyncTestValidation(Timer timer) { finishTest(); delayTestFinish(500); } timer.schedule(100); }); } // to validate async test } public void testUpdateLabelFromServerAtClick()throws Exception { public void testResetLabelOnSecondClick() throws assertEquals(1, RootPanel.get Exception {("slot1").getWidgetCount()); app.clickMeButton.click(); app.clickMeButton.click(); asyncTestValidation(new Timer() { asyncTestValidation(new Timer() { public void run() { public void run() { app.clickMeButton.click(); assertEquals("Client said: "Hello,World!"Server answered: "Hi!"", asyncTestValidation(new Timer() {app.messageLabel.getText()); public void run() { finishTest(); } assertEquals("", }); app.messageLabel.getText()); } finishTest(); } }); } }); } }Sunday, April 17, 2011
  32. 32. package com.mySampleApplication.client; public void testNotifyServerError() throws Exception {import ... final MySampleApplication wrongApp = new MySampleApplication();public class MySampleApplicationTest extends GWTTestCase wrongApp.message = null; //to simulate an error{ from server @Override wrongApp.onModuleLoad(); protected void gwtSetUp() throws Exception { } ...//setup stuff wrongApp.clickMeButton.click(); @Override asyncTestValidation(new Timer() { public String getModuleName() { public void run() {... } // return .gwt.xml name assertEquals("Failed to receive answer from server!", wrongApp.messageLabel.getText()); private void asyncTestValidation(Timer timer) { finishTest(); delayTestFinish(500); } timer.schedule(100); }); } // to validate async test } public void testUpdateLabelFromServerAtClick()throws Exception { public void testResetLabelOnSecondClick() throws assertEquals(1, RootPanel.get Exception {("slot1").getWidgetCount()); app.clickMeButton.click(); app.clickMeButton.click(); asyncTestValidation(new Timer() { asyncTestValidation(new Timer() { public void run() { public void run() { app.clickMeButton.click(); assertEquals("Client said: "Hello,World!"Server answered: "Hi!"", asyncTestValidation(new Timer() {app.messageLabel.getText()); public void run() { finishTest(); } assertEquals("", }); app.messageLabel.getText()); } finishTest(); } }); } So what’s wrong with this? }); } }Sunday, April 17, 2011
  33. 33. package com.mySampleApplication.client; public void testNotifyServerError() throws Exception {import ... final MySampleApplication wrongApp = new MySampleApplication();public class MySampleApplicationTest extends GWTTestCase wrongApp.message = null; //to simulate an error{ from server Slow! it recompiles in Javascript @Override protected void gwtSetUp() throws Exception { } ...//setup stuff wrongApp.onModuleLoad(); wrongApp.clickMeButton.click(); @Override asyncTestValidation(new Timer() { public String getModuleName() { public void run() {... } // return .gwt.xml name assertEquals("Failed to receive answer from server!", wrongApp.messageLabel.getText()); private void asyncTestValidation(Timer timer) { finishTest(); delayTestFinish(500); } timer.schedule(100); }); } // to validate async test } public void testUpdateLabelFromServerAtClick()throws Exception { public void testResetLabelOnSecondClick() throws assertEquals(1, RootPanel.get Exception {("slot1").getWidgetCount()); app.clickMeButton.click(); app.clickMeButton.click(); asyncTestValidation(new Timer() { asyncTestValidation(new Timer() { public void run() { public void run() { app.clickMeButton.click(); assertEquals("Client said: "Hello,World!"Server answered: "Hi!"", asyncTestValidation(new Timer() {app.messageLabel.getText()); public void run() { finishTest(); } assertEquals("", }); app.messageLabel.getText()); } finishTest(); } }); } So what’s wrong with this? }); } }Sunday, April 17, 2011
  34. 34. package com.mySampleApplication.client; public void testNotifyServerError() throws Exception {import ... final MySampleApplication wrongApp = new MySampleApplication();public class MySampleApplicationTest extends GWTTestCase wrongApp.message = null; //to simulate an error{ from server Slow! it recompiles in Javascript @Override protected void gwtSetUp() throws Exception { } ...//setup stuff wrongApp.onModuleLoad(); wrongApp.clickMeButton.click(); @Override asyncTestValidation(new Timer() { public String getModuleName() { public void run() {... } // return .gwt.xml name assertEquals("Failed to receive answer from server!", wrongApp.messageLabel.getText()); private void asyncTestValidation(Timer timer) { finishTest(); delayTestFinish(500); } timer.schedule(100); }); } // to validate async test } public void testUpdateLabelFromServerAtClick()throws Exception { public void testResetLabelOnSecondClick() throws assertEquals(1, RootPanel.get Exception { Fragile, it use whole app("slot1").getWidgetCount()); app.clickMeButton.click(); app.clickMeButton.click(); asyncTestValidation(new Timer() { asyncTestValidation(new Timer() { public void run() { public void run() { app.clickMeButton.click(); assertEquals("Client said: "Hello,World!"Server answered: "Hi!"", asyncTestValidation(new Timer() {app.messageLabel.getText()); public void run() { finishTest(); } assertEquals("", }); app.messageLabel.getText()); } finishTest(); } }); } So what’s wrong with this? }); } }Sunday, April 17, 2011
  35. 35. package com.mySampleApplication.client; public void testNotifyServerError() throws Exception {import ... final MySampleApplication wrongApp = new MySampleApplication();public class MySampleApplicationTest extends GWTTestCase wrongApp.message = null; //to simulate an error{ from server Slow! it recompiles in Javascript @Override protected void gwtSetUp() throws Exception { } ...//setup stuff wrongApp.onModuleLoad(); wrongApp.clickMeButton.click(); @Override asyncTestValidation(new Timer() { public String getModuleName() { public void run() {... } // return .gwt.xml name assertEquals("Failed to receive answer from server!", wrongApp.messageLabel.getText()); private void asyncTestValidation(Timer timer) { finishTest(); delayTestFinish(500); } timer.schedule(100); }); } // to validate async test } public void testUpdateLabelFromServerAtClick()throws Exception { public void testResetLabelOnSecondClick() throws assertEquals(1, RootPanel.get Exception { Fragile, it use whole app("slot1").getWidgetCount()); app.clickMeButton.click(); app.clickMeButton.click(); asyncTestValidation(new Timer() { asyncTestValidation(new Timer() { public void run() { public void run() { app.clickMeButton.click(); assertEquals("Client said: "Hello,World!"Server answered: "Hi!"", asyncTestValidation(new Timer() { Slow! Async tests take timeapp.messageLabel.getText()); public void run() { finishTest(); } assertEquals("", }); app.messageLabel.getText()); } finishTest(); } }); } So what’s wrong with this? }); } }Sunday, April 17, 2011
  36. 36. package com.mySampleApplication.client; public void testNotifyServerError() throws Exception {import ... final MySampleApplication wrongApp = new MySampleApplication();public class MySampleApplicationTest extends GWTTestCase wrongApp.message = null; //to simulate an error{ from server Slow! it recompiles in Javascript @Override protected void gwtSetUp() throws Exception { } ...//setup stuff wrongApp.onModuleLoad(); wrongApp.clickMeButton.click(); @Override asyncTestValidation(new Timer() { public String getModuleName() { public void run() {... } // return .gwt.xml name assertEquals("Failed to receive answer Fragile! from server!", wrongApp.messageLabel.getText()); private void asyncTestValidation(Timer timer) { finishTest(); delayTestFinish(500); } timer.schedule(100); }); } // to validate async test It tests state not iteractions } public void testUpdateLabelFromServerAtClick()throws Exception { public void testResetLabelOnSecondClick() throws assertEquals(1, RootPanel.get Exception { Fragile, it use whole app("slot1").getWidgetCount()); app.clickMeButton.click(); app.clickMeButton.click(); asyncTestValidation(new Timer() { asyncTestValidation(new Timer() { public void run() { public void run() { app.clickMeButton.click(); assertEquals("Client said: "Hello,World!"Server answered: "Hi!"", asyncTestValidation(new Timer() { Slow! Async tests take timeapp.messageLabel.getText()); public void run() { finishTest(); } assertEquals("", }); app.messageLabel.getText()); } finishTest(); } }); } So what’s wrong with this? }); } }Sunday, April 17, 2011
  37. 37. HelloWorld with Tests What we learned?Sunday, April 17, 2011
  38. 38. HelloWorld with Tests What we learned? Gwt HelloWorld can easily be tested with 100% coverage using GWTTestCase.Sunday, April 17, 2011
  39. 39. HelloWorld with Tests What we learned? Gwt HelloWorld can easily be tested with 100% coverage using GWTTestCase. But we need to do better than that!Sunday, April 17, 2011
  40. 40. HelloWorld with Tests What we learned? Gwt HelloWorld can easily be tested with 100% coverage using GWTTestCase. But we need to do better than that! We need to keep GWTTestCase use at minimum and test objects separately.Sunday, April 17, 2011
  41. 41. Ok, now I know I can test all my Gwt classes... But last time I checked TDD meant Test Driven DesignSunday, April 17, 2011
  42. 42. Introducing MVP Remove Presenter and View from ApplicationSunday, April 17, 2011
  43. 43. Introducing MVP Remove Presenter and View from ApplicationSunday, April 17, 2011
  44. 44. Introducing MVP Remove Presenter and View from Application ApplicationSunday, April 17, 2011
  45. 45. Introducing MVP Remove Presenter and View from Application ApplicationSunday, April 17, 2011
  46. 46. Introducing MVP Remove Presenter and View from Application Application PresenterSunday, April 17, 2011
  47. 47. Introducing MVP Remove Presenter and View from Application Application PresenterSunday, April 17, 2011
  48. 48. Introducing MVP Remove Presenter and View from Application Application Services PresenterSunday, April 17, 2011
  49. 49. Introducing MVP Remove Presenter and View from Application Application Services PresenterSunday, April 17, 2011
  50. 50. Introducing MVP Remove Presenter and View from Application Application Services Presenter ViewSunday, April 17, 2011
  51. 51. public class MySampleApplication implements } EntryPoint { } public void onModuleLoad() { }; Presenter presenter = getPresenterFromUrl(); } presenter.activate(); } private static class MyAsyncCallback implements AsyncCallback<String> { private Presenter getPresenterFromUrl() ... //this will read from history private NotificationView view; } } public MyAsyncCallback(NotificationView view) { public class BugListPresenter extends Presenter { this.view = view; ... } public BugListPresenter(BugListView view, MySampleApplicationServiceAsync messageService) { public void onSuccess(String result) { super(view); view.setMessageText(result); this.view = view; } this.messageService = messageService; asyncCallback = new MyAsyncCallback(view); public void onFailure(Throwable throwable) { view.addClickMeHandler(createClickHandler view.setMessageText("Failed to receive ()); answer from server!"); } } } @Override Result of ajax call protected void onShow() { } view.setTitle("Active bugs"); } private ClickHandler createClickHandler() { return new ClickHandler() { on the label public void onClick(ClickEvent event) { if (view.getMessageText().isEmpty()) Application start { messageService.getMessage (message, asyncCallback); Ajax call on click } else { view.setMessageText("");Sunday, April 17, 2011
  52. 52. public class BugListViewFlexTable extends ViewAbstractRoot implements BugListView { public Button clickMeButton = new Button("Click me");; public Label messageLabel = new Label(); public void setTitle(String title) { RootPanel.get("slot1").add(clickMeButton); RootPanel.get("slot2").add(messageLabel); RootPanel.get("title-label").getElement().setInnerText(title); } @Override public void addClickMeHandler(ClickHandler clickHandler) { clickMeButton.addClickHandler(clickHandler); } @Override public void setMessageText(String message) { messageLabel.getElement().setInnerHTML(message); //for html } @Override public String getMessageText() { return messageLabel.getText(); } } View very simple with clear interfaceSunday, April 17, 2011
  53. 53. ublic class BugListViewTest extends GwtTestWithApp { private BugListView bugListView; @Override protected void gwtSetUp() throws Exception { super.gwtSetUp(); bugListView = new BugListViewFlexTable(); } public void testCreateAnEmptyGridOnActivation() throws Exception { bugListView.show(); assertEquals(1, RootPanel.get("wrapper").getWidgetCount()); assertEquals(0, bugListView.getRowCount()); assertEquals("Active bugs", RootPanel.get("title-label").getElement().getInnerText()); } public void testDisplayAndReadTheMessage() throws Exception { bugListView.show(); assertEquals("<div class="gwt-Label"></div>", RootPanel.get("slot2").getElement().getInnerHTML()); bugListView.setMessageText("My message"); assertEquals("<div class="gwt-Label"></div>", RootPanel.get("slot2").getElement().getInnerHTML()); assertEquals("My message", bugListView.getMessageText()); } } View storiesSunday, April 17, 2011
  54. 54. public class BugListPresenterTest { @Test @Before public void shouldShowTheErrorWhenServerFails() public void setUp() throws Exception { throws Exception { clickAnswer = new ClickAnswer(); doAnswer(new MessageErrorAnswer()).when doAnswer(clickAnswer).when (getMessageService).getMessage(anyString(), any (view).addClickMeHandler(any(ClickHandler.class)); (AsyncCallback.class)); doAnswer(new MessageAnswer()).when pres.activate(); (getMessageService).getMessage(anyString(), any (AsyncCallback.class)); verifyViewInvocations(); when(view.getMessageText()).thenReturn(""); clickAnswer.clickHandler.onClick(null); pres = new BugListPresenter(view, verify(getMessageService).getMessage(anyString getMessageService); (), any(AsyncCallback.class)); } verify(view).getMessageText(); @After verify(view).setMessageText("Failed to receive public void dropDown() throws Exception { answer from server!"); Mockito.verifyNoMoreInteractions(view); } Mockito.verifyNoMoreInteractions (getMessageService); @Test } public void shouldResetTheMessageTheSecondClick() throws Exception { @Test when(view.getMessageText()).thenReturn("not public void shouldShowTheMessageOnClick() throws void"); Exception { pres.activate(); pres.activate(); verifyViewInvocations(); verifyViewInvocations(); clickAnswer.clickHandler.onClick(null); clickAnswer.clickHandler.onClick(null); verify(getMessageService).getMessage(anyString (), any(AsyncCallback.class)); verify(view).getMessageText(); verify(view).getMessageText(); verify(view).setMessageText(""); } verify(view).setMessageText("MessageAnswer invoked with: "Hello, World!""); }Sunday, April 17, 2011
  55. 55. public class BugListPresenterTest { @Before Presenter with @Test public void shouldShowTheErrorWhenServerFails() public void setUp() throws Exception { throws Exception { clickAnswer = new ClickAnswer(); doAnswer(clickAnswer).when logic using mocks doAnswer(new MessageErrorAnswer()).when (getMessageService).getMessage(anyString(), any (view).addClickMeHandler(any(ClickHandler.class)); (AsyncCallback.class)); doAnswer(new MessageAnswer()).when (getMessageService).getMessage(anyString(), any for view and pres.activate(); services (AsyncCallback.class)); verifyViewInvocations(); when(view.getMessageText()).thenReturn(""); clickAnswer.clickHandler.onClick(null); pres = new BugListPresenter(view, verify(getMessageService).getMessage(anyString getMessageService); (), any(AsyncCallback.class)); } verify(view).getMessageText(); @After verify(view).setMessageText("Failed to receive public void dropDown() throws Exception { answer from server!"); Mockito.verifyNoMoreInteractions(view); } Mockito.verifyNoMoreInteractions (getMessageService); @Test } public void shouldResetTheMessageTheSecondClick() throws Exception { @Test when(view.getMessageText()).thenReturn("not public void shouldShowTheMessageOnClick() throws void"); Exception { pres.activate(); pres.activate(); verifyViewInvocations(); verifyViewInvocations(); clickAnswer.clickHandler.onClick(null); clickAnswer.clickHandler.onClick(null); verify(getMessageService).getMessage(anyString (), any(AsyncCallback.class)); verify(view).getMessageText(); verify(view).getMessageText(); verify(view).setMessageText(""); } verify(view).setMessageText("MessageAnswer invoked with: "Hello, World!""); }Sunday, April 17, 2011
  56. 56. MVP Unit Tests Client GWT Tests Pure Java pseudo-client Tests Pure Java standard TestsSunday, April 17, 2011
  57. 57. Model View PresenterSunday, April 17, 2011
  58. 58. Model View Presenter • 100% test coverage. To let them drive your design.Sunday, April 17, 2011
  59. 59. Model View Presenter • 100% test coverage. To let them drive your design. • pseudo-client tests split.plain Java. Test Presenters and Model inSunday, April 17, 2011
  60. 60. Model View Presenter • 100% test coverage. To let them drive your design. • pseudo-client tests split.plain Java. Test Presenters and Model in • GwtTests onlystatus.View/Services. shallow one Services have no for Views just a very (MVP not MVC). You can also test the DOM*Sunday, April 17, 2011
  61. 61. Model View Presenter • 100% test coverage. To let them drive your design. • pseudo-client tests split.plain Java. Test Presenters and Model in • GwtTests onlystatus.View/Services. shallow one Services have no for Views just a very (MVP not MVC). You can also test the DOM* • asyncTests only are not in the View.Services. That’s why Services for testing theSunday, April 17, 2011
  62. 62. Model View Presenter • 100% test coverage. To let them drive your design. • pseudo-client tests split.plain Java. Test Presenters and Model in • GwtTests onlystatus.View/Services. shallow one Services have no for Views just a very (MVP not MVC). You can also test the DOM* • asyncTests only are not in the View.Services. That’s why Services for testing the *in lack of something betterSunday, April 17, 2011
  63. 63. If you have to remember just a Model View Presenter slide please remember this one! • 100% test coverage. To let them drive your design. • pseudo-client tests split.plain Java. Test Presenters and Model in • GwtTests onlystatus.View/Services. shallow one Services have no for Views just a very (MVP not MVC). You can also test the DOM* • asyncTests only are not in the View.Services. That’s why Services for testing the *in lack of something betterSunday, April 17, 2011
  64. 64. Example BugTrackerSunday, April 17, 2011
  65. 65. Example BugTracker • First theTDD serverside ModelSunday, April 17, 2011
  66. 66. Example BugTracker • First theTDD serverside Model • Then the View + client TDD developer mode designSunday, April 17, 2011
  67. 67. Example BugTracker • First theTDD serverside Model • Then the View + client TDD developer mode design • Continue with Presenter pseudo-client TDDSunday, April 17, 2011
  68. 68. Example BugTracker • First theTDD serverside Model • Then the View + client TDD developer mode design • Continue with Presenter pseudo-client TDD • Finish with the Plumbing Integration TestsSunday, April 17, 2011
  69. 69. NetNumero.comSunday, April 17, 2011
  70. 70. NetNumero.com • We started in TDD only on the serverSunday, April 17, 2011
  71. 71. NetNumero.com • We started in TDD only on the server • Then we refactored to GOOS style TDDSunday, April 17, 2011
  72. 72. NetNumero.com • We started in TDD only on the server • Then we refactored to GOOS style TDD • Now we’re doing also Views in TDDSunday, April 17, 2011
  73. 73. NetNumero.com • We started in TDD only on the server • Then we refactored to GOOS style TDD • Now we’re doing also Views in TDD • We also started using Cucumber for Acceptance TestsSunday, April 17, 2011
  74. 74. NetNumero.com • We started in TDD only on the server • Then we refactored to GOOS style TDD • Now we’re doing also Views in TDD • We also started using Cucumber for Acceptance Tests • So which design emerged?Sunday, April 17, 2011
  75. 75. Browser - JavaScript Dual-Exagon Events Architecture User Ajax Webserver - JavaSunday, April 17, 2011
  76. 76. Browser - JavaScript Dual-Exagon Events Architecture User Ajax • All client code is on a single html page. Webserver - JavaSunday, April 17, 2011
  77. 77. Browser - JavaScript Dual-Exagon Events Architecture User Ajax • All client code is on a single html page. • Internal navigation with dynamic bookmark Webserver - JavaSunday, April 17, 2011
  78. 78. Browser - JavaScript Dual-Exagon Events Architecture User Ajax • All client code is on a single html page. • Internal navigation with dynamic bookmark • Completely sessionless server (REST or GWT-RPC) Webserver - JavaSunday, April 17, 2011
  79. 79. Client Browser - JavaScript S /J ets dg View Wi Model Events GWT y tor Module is H r se Presenter ow Br Services Async Services based on generics AjaxSunday, April 17, 2011
  80. 80. Client Browser - JavaScript Write your own S /J ets widgets for UI dg View Wi Model Events GWT y tor Module is H r se Presenter ow Br Services Async Services based on generics AjaxSunday, April 17, 2011
  81. 81. Client Browser - JavaScript Write your own S /J ets widgets for UI dg View Wi Model Events Browser GWT y tor Module is H events based r se Presenter ow Br Services Async Services based on generics AjaxSunday, April 17, 2011
  82. 82. Server Ajax Servlet Auth-Auth gs Lo Audit Commands Model DAO Persistence Webserver - JavaSunday, April 17, 2011
  83. 83. Server Ajax Get the ajax call, Servlet check the security, Auth-Auth gs process the Lo Audit command Commands Model DAO Persistence Webserver - JavaSunday, April 17, 2011
  84. 84. Server Ajax Get the ajax call, Servlet check the security, Auth-Auth gs process the Lo Audit command Commands Model Commands call the DAO model and the Persistence persistence layer Webserver - JavaSunday, April 17, 2011
  85. 85. When things grow upSunday, April 17, 2011
  86. 86. When things grow up • Code splitSunday, April 17, 2011
  87. 87. When things grow up • Code split • Presenter proxy patternSunday, April 17, 2011
  88. 88. When things grow up • Code split • Presenter proxy pattern • Modular Views and PresentersSunday, April 17, 2011
  89. 89. Code split reportSunday, April 17, 2011
  90. 90. Code split report This is your obfuscated total javascript code.Sunday, April 17, 2011
  91. 91. Code split report This is your obfuscated total javascript code. This is your initial download.Sunday, April 17, 2011
  92. 92. Code split report This is your obfuscated total javascript code. This is your initial download. This is your second download. We can split again anyway...Sunday, April 17, 2011
  93. 93. Split codeSunday, April 17, 2011
  94. 94. • examples:Sunday, April 17, 2011
  95. 95. Sparse thoughts • It’s not that I don’t like JS. It’s all about tools and having same language everywhere • The issue with 100% coverage it’s not really about tests. If there is a 1% that I cannot test there must be a design problem there. • Javascript threads and other differences between Java and GWT compilable Java • View Dom Manipulation and xpath tests • View test first with UIBindings and widgetsSunday, April 17, 2011
  96. 96. The future...Sunday, April 17, 2011
  97. 97. The future...Sunday, April 17, 2011
  98. 98. The future... my wish list:Sunday, April 17, 2011
  99. 99. The future... my wish list: •Incremental compileSunday, April 17, 2011
  100. 100. The future... my wish list: •Incremental compile •Multi browsers javascriptSunday, April 17, 2011
  101. 101. The future... my wish list: •Incremental compile •Multi browsers javascript •Other languages (Python, Scala)Sunday, April 17, 2011
  102. 102. The future... my wish list: •Incremental compile •Multi browsers javascript •Other languages (Python, Scala) •GWT toolkit for JS server side?Sunday, April 17, 2011
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×