SlideShare a Scribd company logo
1 of 102
Download to read offline
April 13-16, 2011. Oxford, UK


                          Writing web UI in
                         Testfirst fashion with
                                GWT
                                 Uberto Barbini
                               uberto@ubiland.net
                                twitter: @ramtop




Sunday, April 17, 2011
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
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
http://netnumero.com




Sunday, April 17, 2011
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
Four Noble Truths
                         of Buddhism




Sunday, April 17, 2011
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 Path


Sunday, April 17, 2011
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 Rest
Sunday, April 17, 2011
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 Rest
Sunday, April 17, 2011
What’s GWT
                          anyway?



Sunday, April 17, 2011
What’s GWT
                           anyway?

                                Short version:
                         Java to Javascript compiler

Sunday, April 17, 2011
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.html
Sunday, April 17, 2011
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 seconds



Sunday, April 17, 2011
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 seconds



Sunday, April 17, 2011
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
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.190s




Sunday, April 17, 2011
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




Sunday, April 17, 2011
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 minutes

Sunday, April 17, 2011
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.html



Sunday, April 17, 2011
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.html



Sunday, April 17, 2011
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
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
GWT magic 3
                         RPC services




Sunday, April 17, 2011
GWT magic 3
                         RPC services




                         1

Sunday, April 17, 2011
GWT magic 3
                         RPC services




                         1      2

Sunday, April 17, 2011
GWT magic 3
                         RPC services




                         1      2       3

Sunday, April 17, 2011
Enough talk, let’s code!
Sunday, April 17, 2011
• example of Hello in devmode
                     • example in IntelliJ of BugList Hello


Sunday, April 17, 2011
Example HelloWorld
                                     Starting with the
                                     gwt helloworld
                                     example we can
                                     write test to cover
                                     everything.

                                     Let’s see how...




Sunday, April 17, 2011
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
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
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
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
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
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 time
app.messageLabel.getText());                                                   public void run() {
                finishTest();
            }                                                                      assertEquals("",
        });                                                app.messageLabel.getText());
    }                                                                              finishTest();
                                                                               }
                                                                           });
                                                                       }

   So what’s wrong with this?
                                                                   });
                                                               }
                                                           }



Sunday, April 17, 2011
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 time
app.messageLabel.getText());                                                   public void run() {
                finishTest();
            }                                                                      assertEquals("",
        });                                                app.messageLabel.getText());
    }                                                                              finishTest();
                                                                               }
                                                                           });
                                                                       }

   So what’s wrong with this?
                                                                   });
                                                               }
                                                           }



Sunday, April 17, 2011
HelloWorld with Tests
                         What we learned?




Sunday, April 17, 2011
HelloWorld with Tests
                         What we learned?
                         Gwt HelloWorld can easily be tested with
                         100% coverage using GWTTestCase.




Sunday, April 17, 2011
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
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
Ok, now I know
                      I can test all my
                      Gwt classes...




                            But last time I
                         checked TDD meant
                         Test Driven Design




Sunday, April 17, 2011
Introducing MVP
           Remove Presenter and View from Application




Sunday, April 17, 2011
Introducing MVP
           Remove Presenter and View from Application




Sunday, April 17, 2011
Introducing MVP
           Remove Presenter and View from Application
                                   Application




Sunday, April 17, 2011
Introducing MVP
           Remove Presenter and View from Application
                                   Application




Sunday, April 17, 2011
Introducing MVP
           Remove Presenter and View from Application
                                      Application




                         Presenter

Sunday, April 17, 2011
Introducing MVP
           Remove Presenter and View from Application
                                      Application




                         Presenter

Sunday, April 17, 2011
Introducing MVP
           Remove Presenter and View from Application
                                      Application




                                        Services


                         Presenter

Sunday, April 17, 2011
Introducing MVP
           Remove Presenter and View from Application
                                      Application




                                        Services


                         Presenter

Sunday, April 17, 2011
Introducing MVP
           Remove Presenter and View from Application
                                      Application




                                        Services


                         Presenter        View

Sunday, April 17, 2011
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
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 interface


Sunday, April 17, 2011
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 stories

Sunday, April 17, 2011
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
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
MVP Unit Tests

                                   Client GWT Tests



                                      Pure Java
                                  pseudo-client Tests

                                       Pure Java
                                    standard Tests

Sunday, April 17, 2011
Model View Presenter




Sunday, April 17, 2011
Model View Presenter
                     • 100% test coverage.
                         To let them drive your design.




Sunday, April 17, 2011
Model View Presenter
                     • 100% test coverage.
                         To let them drive your design.
                     • pseudo-client tests split.plain Java.
                       Test Presenters and Model in




Sunday, April 17, 2011
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
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



Sunday, April 17, 2011
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 better
Sunday, April 17, 2011
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 better
Sunday, April 17, 2011
Example BugTracker




Sunday, April 17, 2011
Example BugTracker
                     • First theTDD
                       serverside
                                  Model




Sunday, April 17, 2011
Example BugTracker
                     • First theTDD
                       serverside
                                  Model

                     • Then the View + client TDD
                       developer mode design




Sunday, April 17, 2011
Example BugTracker
                     • First theTDD
                       serverside
                                  Model

                     • Then the View + client TDD
                       developer mode design

                     • Continue with Presenter
                       pseudo-client TDD




Sunday, April 17, 2011
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 Tests


Sunday, April 17, 2011
NetNumero.com




Sunday, April 17, 2011
NetNumero.com
                     • We started in TDD only on the server




Sunday, April 17, 2011
NetNumero.com
                     • We started in TDD only on the server
                     • Then we refactored to GOOS style TDD




Sunday, April 17, 2011
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



Sunday, April 17, 2011
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




Sunday, April 17, 2011
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
Browser - JavaScript


       Dual-Exagon              Events



       Architecture      User




                                             Ajax
                                Webserver - Java
Sunday, April 17, 2011
Browser - JavaScript


       Dual-Exagon                                     Events



       Architecture                             User




                                                                    Ajax
           •       All client code is on a single
                   html page.




                                                       Webserver - Java
Sunday, April 17, 2011
Browser - JavaScript


       Dual-Exagon                                     Events



       Architecture                             User




                                                                    Ajax
           •       All client code is on a single
                   html page.

           •       Internal navigation with
                   dynamic bookmark


                                                       Webserver - Java
Sunday, April 17, 2011
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 - Java
Sunday, April 17, 2011
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


                                                                   Ajax
Sunday, April 17, 2011
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


                                                                   Ajax
Sunday, April 17, 2011
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


                                                                   Ajax
Sunday, April 17, 2011
Server




                                                     Ajax
                                                     Servlet


                                                   Auth-Auth




                                      gs
                                     Lo
                                           Audit

                                                      Commands



                                                                  Model


                                                      DAO


                                                    Persistence




                         Webserver - Java
Sunday, April 17, 2011
Server




                                                     Ajax
   Get the ajax call,                                Servlet

   check the security,                             Auth-Auth




                                      gs
       process the




                                     Lo
                                           Audit

        command                                       Commands



                                                                  Model


                                                      DAO


                                                    Persistence




                         Webserver - Java
Sunday, April 17, 2011
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 - Java
Sunday, April 17, 2011
When things grow up




Sunday, April 17, 2011
When things grow up

                     • Code split




Sunday, April 17, 2011
When things grow up

                     • Code split
                     • Presenter proxy pattern


Sunday, April 17, 2011
When things grow up

                     • Code split
                     • Presenter proxy pattern
                     • Modular Views and Presenters

Sunday, April 17, 2011
Code split report




Sunday, April 17, 2011
Code split report
                                 This is your obfuscated total
                                       javascript code.




Sunday, April 17, 2011
Code split report
                                 This is your obfuscated total
                                       javascript code.


                                   This is your initial download.




Sunday, April 17, 2011
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
Split code




Sunday, 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 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 widgets
Sunday, April 17, 2011
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 compile




Sunday, April 17, 2011
The future...
                     my wish list:
                     •Incremental compile
                     •Multi browsers javascript




Sunday, April 17, 2011
The future...
                     my wish list:
                     •Incremental compile
                     •Multi browsers javascript
                     •Other languages (Python, Scala)



Sunday, April 17, 2011
The future...
                     my wish list:
                     •Incremental compile
                     •Multi browsers javascript
                     •Other languages (Python, Scala)
                     •GWT toolkit for JS server side?


Sunday, April 17, 2011

More Related Content

Similar to Develop Gwt application in TDD

OpenDaylight Developers Experience 1.5: Eclipse Setup, HOT reload, future plans
OpenDaylight Developers Experience 1.5: Eclipse Setup, HOT reload, future plansOpenDaylight Developers Experience 1.5: Eclipse Setup, HOT reload, future plans
OpenDaylight Developers Experience 1.5: Eclipse Setup, HOT reload, future plansMichael Vorburger
 
20110903 candycane
20110903 candycane20110903 candycane
20110903 candycaneYusuke Ando
 
Coding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedCoding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedElizabeth Quinn-Woods
 
Coding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedCoding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedMadeline Gauthier
 
Coding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedCoding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedK. Dachos
 
JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011Charles Nutter
 
Introduction to go lang
Introduction to go langIntroduction to go lang
Introduction to go langAmal Mohan N
 
Ruby JIT Compilation - Mykhail Bortnyk
Ruby JIT Compilation - Mykhail Bortnyk Ruby JIT Compilation - Mykhail Bortnyk
Ruby JIT Compilation - Mykhail Bortnyk Ruby Meditation
 
Ruby JIT Compilation
Ruby JIT CompilationRuby JIT Compilation
Ruby JIT CompilationAmoniac OÜ
 
Learn java in one day and learn it well 2016 jamie chan
Learn java in one day and learn it well 2016   jamie chanLearn java in one day and learn it well 2016   jamie chan
Learn java in one day and learn it well 2016 jamie chananand_study
 
Maven: from Scratch to Production (.pdf)
Maven: from Scratch to Production (.pdf)Maven: from Scratch to Production (.pdf)
Maven: from Scratch to Production (.pdf)Johan Mynhardt
 
Java EE Servlet JSP Tutorial- Cookbook 1
Java EE Servlet JSP Tutorial- Cookbook 1Java EE Servlet JSP Tutorial- Cookbook 1
Java EE Servlet JSP Tutorial- Cookbook 1billdigman
 
7 Habits of Highly Effective Jenkins Users
7 Habits of Highly Effective Jenkins Users7 Habits of Highly Effective Jenkins Users
7 Habits of Highly Effective Jenkins UsersAndrew Bayer
 
Angular 2 vs React. What to chose in 2017?
Angular 2 vs React. What to chose in 2017?Angular 2 vs React. What to chose in 2017?
Angular 2 vs React. What to chose in 2017?TechMagic
 
Is Advanced Verification for FPGA based Logic needed
Is Advanced Verification for FPGA based Logic neededIs Advanced Verification for FPGA based Logic needed
Is Advanced Verification for FPGA based Logic neededchiportal
 
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...mCloud
 
From hello world to goodbye code
From hello world to goodbye codeFrom hello world to goodbye code
From hello world to goodbye codeKim Moir
 

Similar to Develop Gwt application in TDD (20)

Java (1)
Java (1)Java (1)
Java (1)
 
OpenDaylight Developers Experience 1.5: Eclipse Setup, HOT reload, future plans
OpenDaylight Developers Experience 1.5: Eclipse Setup, HOT reload, future plansOpenDaylight Developers Experience 1.5: Eclipse Setup, HOT reload, future plans
OpenDaylight Developers Experience 1.5: Eclipse Setup, HOT reload, future plans
 
20110903 candycane
20110903 candycane20110903 candycane
20110903 candycane
 
Coding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedCoding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever Changed
 
Coding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedCoding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever Changed
 
Coding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedCoding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever Changed
 
JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011
 
GWT Reloaded
GWT ReloadedGWT Reloaded
GWT Reloaded
 
Introduction to go lang
Introduction to go langIntroduction to go lang
Introduction to go lang
 
Ruby JIT Compilation - Mykhail Bortnyk
Ruby JIT Compilation - Mykhail Bortnyk Ruby JIT Compilation - Mykhail Bortnyk
Ruby JIT Compilation - Mykhail Bortnyk
 
Ruby JIT Compilation
Ruby JIT CompilationRuby JIT Compilation
Ruby JIT Compilation
 
Learn java in one day and learn it well 2016 jamie chan
Learn java in one day and learn it well 2016   jamie chanLearn java in one day and learn it well 2016   jamie chan
Learn java in one day and learn it well 2016 jamie chan
 
Maven: from Scratch to Production (.pdf)
Maven: from Scratch to Production (.pdf)Maven: from Scratch to Production (.pdf)
Maven: from Scratch to Production (.pdf)
 
Java EE Servlet JSP Tutorial- Cookbook 1
Java EE Servlet JSP Tutorial- Cookbook 1Java EE Servlet JSP Tutorial- Cookbook 1
Java EE Servlet JSP Tutorial- Cookbook 1
 
7 Habits of Highly Effective Jenkins Users
7 Habits of Highly Effective Jenkins Users7 Habits of Highly Effective Jenkins Users
7 Habits of Highly Effective Jenkins Users
 
Angular 2 vs React. What to chose in 2017?
Angular 2 vs React. What to chose in 2017?Angular 2 vs React. What to chose in 2017?
Angular 2 vs React. What to chose in 2017?
 
Is Advanced Verification for FPGA based Logic needed
Is Advanced Verification for FPGA based Logic neededIs Advanced Verification for FPGA based Logic needed
Is Advanced Verification for FPGA based Logic needed
 
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
Developers’ mDay u Banjoj Luci - Duško Bajić, Kotlin User Group Bosnia – Kotl...
 
From hello world to goodbye code
From hello world to goodbye codeFrom hello world to goodbye code
From hello world to goodbye code
 
Build tool
Build toolBuild tool
Build tool
 

More from Uberto Barbini

CQRS with Event Source in Functional sauce served by Kotlin
CQRS with Event Source in Functional sauce served by Kotlin CQRS with Event Source in Functional sauce served by Kotlin
CQRS with Event Source in Functional sauce served by Kotlin Uberto Barbini
 
It's All About Morphisms
It's All About MorphismsIt's All About Morphisms
It's All About MorphismsUberto Barbini
 
The Role of Testing in DevOps
The Role of Testing in DevOpsThe Role of Testing in DevOps
The Role of Testing in DevOpsUberto Barbini
 
When Tdd Goes Awry (IAD 2013)
When Tdd Goes Awry (IAD 2013)When Tdd Goes Awry (IAD 2013)
When Tdd Goes Awry (IAD 2013)Uberto Barbini
 
Boost your-oop-with-fp
Boost your-oop-with-fpBoost your-oop-with-fp
Boost your-oop-with-fpUberto Barbini
 

More from Uberto Barbini (9)

CQRS with Event Source in Functional sauce served by Kotlin
CQRS with Event Source in Functional sauce served by Kotlin CQRS with Event Source in Functional sauce served by Kotlin
CQRS with Event Source in Functional sauce served by Kotlin
 
Go kotlin, Go!
Go kotlin, Go!Go kotlin, Go!
Go kotlin, Go!
 
It's All About Morphisms
It's All About MorphismsIt's All About Morphisms
It's All About Morphisms
 
Legacy is Good
Legacy is GoodLegacy is Good
Legacy is Good
 
The Role of Testing in DevOps
The Role of Testing in DevOpsThe Role of Testing in DevOps
The Role of Testing in DevOps
 
When Tdd Goes Awry (IAD 2013)
When Tdd Goes Awry (IAD 2013)When Tdd Goes Awry (IAD 2013)
When Tdd Goes Awry (IAD 2013)
 
When Tdd Goes Awry
When Tdd Goes AwryWhen Tdd Goes Awry
When Tdd Goes Awry
 
Boost your-oop-with-fp
Boost your-oop-with-fpBoost your-oop-with-fp
Boost your-oop-with-fp
 
The Effective Team
The Effective TeamThe Effective Team
The Effective Team
 

Recently uploaded

08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 

Recently uploaded (20)

08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 

Develop Gwt application in TDD

  • 1. April 13-16, 2011. Oxford, UK Writing web UI in Testfirst fashion with GWT Uberto Barbini uberto@ubiland.net twitter: @ramtop Sunday, April 17, 2011
  • 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. 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
  • 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. Four Noble Truths of Buddhism Sunday, April 17, 2011
  • 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 Path Sunday, April 17, 2011
  • 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 Rest Sunday, April 17, 2011
  • 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 Rest Sunday, April 17, 2011
  • 10. What’s GWT anyway? Sunday, April 17, 2011
  • 11. What’s GWT anyway? Short version: Java to Javascript compiler Sunday, April 17, 2011
  • 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.html Sunday, April 17, 2011
  • 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 seconds Sunday, April 17, 2011
  • 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 seconds Sunday, April 17, 2011
  • 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. 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.190s Sunday, April 17, 2011
  • 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.190s Sunday, April 17, 2011
  • 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 minutes Sunday, April 17, 2011
  • 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.html Sunday, April 17, 2011
  • 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.html Sunday, April 17, 2011
  • 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. 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. GWT magic 3 RPC services Sunday, April 17, 2011
  • 24. GWT magic 3 RPC services 1 Sunday, April 17, 2011
  • 25. GWT magic 3 RPC services 1 2 Sunday, April 17, 2011
  • 26. GWT magic 3 RPC services 1 2 3 Sunday, April 17, 2011
  • 27. Enough talk, let’s code! Sunday, April 17, 2011
  • 28. • example of Hello in devmode • example in IntelliJ of BugList Hello Sunday, April 17, 2011
  • 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. 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. 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. 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. 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. 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. 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 time app.messageLabel.getText()); public void run() { finishTest(); } assertEquals("", }); app.messageLabel.getText()); } finishTest(); } }); } So what’s wrong with this? }); } } Sunday, April 17, 2011
  • 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 time app.messageLabel.getText()); public void run() { finishTest(); } assertEquals("", }); app.messageLabel.getText()); } finishTest(); } }); } So what’s wrong with this? }); } } Sunday, April 17, 2011
  • 37. HelloWorld with Tests What we learned? Sunday, April 17, 2011
  • 38. HelloWorld with Tests What we learned? Gwt HelloWorld can easily be tested with 100% coverage using GWTTestCase. Sunday, April 17, 2011
  • 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. 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. Ok, now I know I can test all my Gwt classes... But last time I checked TDD meant Test Driven Design Sunday, April 17, 2011
  • 42. Introducing MVP Remove Presenter and View from Application Sunday, April 17, 2011
  • 43. Introducing MVP Remove Presenter and View from Application Sunday, April 17, 2011
  • 44. Introducing MVP Remove Presenter and View from Application Application Sunday, April 17, 2011
  • 45. Introducing MVP Remove Presenter and View from Application Application Sunday, April 17, 2011
  • 46. Introducing MVP Remove Presenter and View from Application Application Presenter Sunday, April 17, 2011
  • 47. Introducing MVP Remove Presenter and View from Application Application Presenter Sunday, April 17, 2011
  • 48. Introducing MVP Remove Presenter and View from Application Application Services Presenter Sunday, April 17, 2011
  • 49. Introducing MVP Remove Presenter and View from Application Application Services Presenter Sunday, April 17, 2011
  • 50. Introducing MVP Remove Presenter and View from Application Application Services Presenter View Sunday, April 17, 2011
  • 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. 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 interface Sunday, April 17, 2011
  • 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 stories Sunday, April 17, 2011
  • 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. 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. MVP Unit Tests Client GWT Tests Pure Java pseudo-client Tests Pure Java standard Tests Sunday, April 17, 2011
  • 58. Model View Presenter • 100% test coverage. To let them drive your design. Sunday, April 17, 2011
  • 59. Model View Presenter • 100% test coverage. To let them drive your design. • pseudo-client tests split.plain Java. Test Presenters and Model in Sunday, April 17, 2011
  • 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. 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 Sunday, April 17, 2011
  • 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 better Sunday, April 17, 2011
  • 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 better Sunday, April 17, 2011
  • 65. Example BugTracker • First theTDD serverside Model Sunday, April 17, 2011
  • 66. Example BugTracker • First theTDD serverside Model • Then the View + client TDD developer mode design Sunday, April 17, 2011
  • 67. Example BugTracker • First theTDD serverside Model • Then the View + client TDD developer mode design • Continue with Presenter pseudo-client TDD Sunday, April 17, 2011
  • 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 Tests Sunday, April 17, 2011
  • 70. NetNumero.com • We started in TDD only on the server Sunday, April 17, 2011
  • 71. NetNumero.com • We started in TDD only on the server • Then we refactored to GOOS style TDD Sunday, April 17, 2011
  • 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 TDD Sunday, April 17, 2011
  • 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 Tests Sunday, April 17, 2011
  • 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. Browser - JavaScript Dual-Exagon Events Architecture User Ajax Webserver - Java Sunday, April 17, 2011
  • 76. Browser - JavaScript Dual-Exagon Events Architecture User Ajax • All client code is on a single html page. Webserver - Java Sunday, April 17, 2011
  • 77. Browser - JavaScript Dual-Exagon Events Architecture User Ajax • All client code is on a single html page. • Internal navigation with dynamic bookmark Webserver - Java Sunday, April 17, 2011
  • 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 - Java Sunday, April 17, 2011
  • 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 Ajax Sunday, April 17, 2011
  • 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 Ajax Sunday, April 17, 2011
  • 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 Ajax Sunday, April 17, 2011
  • 82. Server Ajax Servlet Auth-Auth gs Lo Audit Commands Model DAO Persistence Webserver - Java Sunday, April 17, 2011
  • 83. Server Ajax Get the ajax call, Servlet check the security, Auth-Auth gs process the Lo Audit command Commands Model DAO Persistence Webserver - Java Sunday, April 17, 2011
  • 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 - Java Sunday, April 17, 2011
  • 85. When things grow up Sunday, April 17, 2011
  • 86. When things grow up • Code split Sunday, April 17, 2011
  • 87. When things grow up • Code split • Presenter proxy pattern Sunday, April 17, 2011
  • 88. When things grow up • Code split • Presenter proxy pattern • Modular Views and Presenters Sunday, April 17, 2011
  • 89. Code split report Sunday, April 17, 2011
  • 90. Code split report This is your obfuscated total javascript code. Sunday, April 17, 2011
  • 91. Code split report This is your obfuscated total javascript code. This is your initial download. Sunday, April 17, 2011
  • 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
  • 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 widgets Sunday, April 17, 2011
  • 98. The future... my wish list: Sunday, April 17, 2011
  • 99. The future... my wish list: •Incremental compile Sunday, April 17, 2011
  • 100. The future... my wish list: •Incremental compile •Multi browsers javascript Sunday, April 17, 2011
  • 101. The future... my wish list: •Incremental compile •Multi browsers javascript •Other languages (Python, Scala) Sunday, April 17, 2011
  • 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