SlideShare une entreprise Scribd logo
1  sur  102
Télécharger pour lire hors ligne
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

Contenu connexe

Similaire à Develop Gwt application in TDD

20110903 candycane
20110903 candycane20110903 candycane
20110903 candycane
Yusuke Ando
 
Coding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedCoding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever Changed
Elizabeth Quinn-Woods
 
Coding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedCoding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever Changed
Madeline Gauthier
 
Coding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever ChangedCoding With JRebel - Java Forever Changed
Coding With JRebel - Java Forever Changed
K. Dachos
 
JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011JVM for Dummies - OSCON 2011
JVM for Dummies - OSCON 2011
Charles Nutter
 
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
billdigman
 

Similaire à 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
 

Plus de Uberto 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-fp
Uberto Barbini
 

Plus de 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
 

Dernier

Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
Joaquim Jorge
 

Dernier (20)

Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
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
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony 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
 
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
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
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
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 

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