Florian Felberbauer | Cenarion
MVP mit dem Google Web Toolkit
• Enterprise-Applikationen
• Versicherungsbranche
• Java
• 5 Jahre GWT
2
MVP
3
M
V
P
aking
acation
lans
?
MVP
4
M
V
P
odel
iew
resenter
!
Ablauf
• Das Prinzip von MVP
• MVP mit GWT
• Activities/Places
• Testing
5
• 1996 von Mike Potel
• Verwandt mit MVC
• Ziele
– Verantwortlichkeiten trennen
– Flexibilität von UIs bei Änderungen des
Models erhöhen
– Testbarkeit der Applikationslogik
Model View Presenter
6
7
Model
Presenter
View
MVC - MVP
Model
Controller View
Von MVC zu MVP
UI
Wie interagieren User
mit dem UI?
Daten
Wie verwalte ich meine
Daten?
8
Daten
Wie sehen die Daten aus?
9
• RDMS
• NoSQL
• Service
• …
Daten
Wie sehen die Daten aus?
Wie werden die Daten spezifiziert?
10
Selektionen der Daten
• z.B. Filterung nach ID, Berechtigungen, …
• oder Darstellung derselben Daten in versch. Kontext
Daten
Wie sehen die Daten aus?
Wie werden die Daten spezifiziert?
Wie werden die Daten modifiziert?
11
• Änderung der Daten auf Selektionen: Insert, Update, …
UI
Wie werden Daten dargestellt?
12
• Welche Widgets werden benützt?
• Wie sehen versch. Views für versch. Benutzergruppen aus?
UI
Wie werden Daten dargestellt?
Wie verändern Events die Daten?
13
• Datenänderung durch Events (Klick, Drag&Drop, …)
UI
Wie werden Daten dargestellt?
Wie verändern Events die Daten?
Wie fügt man alles zusammen?
14
= Presenter – Businesslogik verbindet Daten und UI
Kapselung der Applikation in Client und
Server
Security
15
Kapselung der Applikation in Client und
Server
Security
16
!Client untrustable! Security zumindest auf Serverseite
Vorteile von MVP
• Trennung von Model und View
→ mehr Flexibilität
• Ein Model – mehrere Views
• Skalierbarkeit
• Testbarkeit
17
MVP in GWT
18
Server
Client
Model
Presenter
View
Datenanbindung,
Businesstransaktionen
UI-Widgets, I18n,
Event-Handling, Display-Logik
View mit Daten füttern,
Applikationslogik
Display-Logik vs.
Applikationslogik
19
Unit-Test → Applikationslogik
Warum MVP in GWT?
• Arbeitsteilung
– Lose Kopplung UI – Logik
– Struktur erleichtert Orientierung
• Testbarkeit
20
Warum MVP in GWT?
• Arbeitsteilung
• Testbarkeit
21
Warum MVP in GWT?
• Arbeitsteilung
• Testbarkeit
– UI-Komponenten in GWT:
• Schwer testbar (GWT-Eigenheiten wie
GWT.create())
• Tests langsam
22
Warum MVP in GWT?
• Arbeitsteilung
• Testbarkeit
– UI-Komponenten in GWT:
• Schwer testbar
• Tests langsam (HTMLUnit, native JS)
23
Warum MVP in GWT?
• Arbeitsteilung
• Testbarkeit
– UI-Komponenten in GWT:
• Schwer testbar
• Tests langsam
– Abgrenzung Applikations-Logik von
Display-Logik!
24
Activities & Places
• Browser-History
• URL-Fragment = Place
– .../index.html#SearchPlace!bmw!pkw
• Place repräsentiert State
• Activity
– Kommunikation mit Serverseite
– Daten laden & UI initialisieren
25
State
26
Place Session
Primitive Werte
Objekt-Ids
Authentifizierung
Sprache
Presenter = Activity
Presenter
(Activity)
Place
View
hält State für
initialisiert
Model kommuniziert mit
27
aktualisiert
UiBinder
28
• Trennung Markup und Displaylogik
• Reines Markup in XML File
• Wird in HTML übersetzt
• Code in Java-Klasse
• Compile-time checking von Referenzen
Beispiel: Suche
29
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:Label text="Suche nach beschädigtem Fahrzeug" />
<g:Label text="Fahrgestell-Nr." />
<g:TextBox ui:field="vehicleId" />
<g:Label text="Marke" />
<g:TextBox ui:field="brand" />
<g:Label text="Fahrzeugtyp"/>
<g:ListBox ui:field="type" />
<g:Button text="OK“ ui:field="btnOk" />
<g:Button text="Zurücksetzen" />
</ui:UiBinder>
30
Beispiel: SearchViewImpl.ui.xml
 <input type="text" … />
 <input type="text" … />
 <select…><option>…
 <input type="button" … />
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:Label text="Suche nach beschädigtem Fahrzeug" />
<g:Label text="Fahrgestell-Nr." />
<g:TextBox ui:field="vehicleId" />
<g:Label text="Marke" />
<g:TextBox ui:field="brand" />
<g:Label text="Fahrzeugtyp"/>
<g:ListBox ui:field="type" />
<g:Button text="OK“ ui:field="btnOk" />
<g:Button text="Zurücksetzen" />
<g:Label ui:field="errorText" />
</ui:UiBinder>
31
Beispiel: SearchViewImpl.ui.xml
 <input type="text" … />
 <input type="text" … />
 <select…><option>…
 <input type="button" … />
Beispiel: SearchViewImpl
public class SearchViewImpl extends Composite {
/** View enthält nur EventHandling,
keine Applikationslogik */
@UiField TextBox vehicleId, brand;
@UiField ListBox type;
@UiField Label errorText;
private SearchPresenter presenter;
@UiHandler("btnOk")
public void onOkClick(ClickEvent event) {
presenter.searchOkClicked(); //delegate to presenter
}
}
32
Beispiel: Presenter
private DamagedVehicleRequest request;
private SearchView view;
public void searchOkClicked() {
if (!validVehicleId(view.getVin())) {
view.setErrorText("Fehlermeldung");
} else {
request.search(view.getVin(), view.getBrand(), view.getType())
.fire(new Receiver …);
}
}
33
Klassen/Dateien
34
SearchPlace
SearchView.ui.xml
UiBinder
Place
AbstractActivity
ActivityMapper
Composite
Lookup / Dependency Injection
SearchPresenter
SearchView
Interfaces?
35
SearchPresenter
SearchView
ISearchPresenter
ISearchView
Testbarkeit?
36
private DamagedVehicleRequest request;
private SearchView view;
public void searchOkClicked() {
if (!validVehicleId(view.getVin())) {
view.setErrorText("Fehlermeldung");
} else {
request.search(view.getVin(), view.getBrand(), view.getType())
.fire(new Receiver …);
}
}
Beispiel: Presenter
37
Beispiel: Presenter-Test
//Mocking der Serverkommunikation
private final Request<DamagedVehicleProxy> requestMock =
mock(Request.class);
private DamagedVehicleRequest requestContextMock;
private SearchPresenter presenter;
//Mocking des View-Interfaces
private SearchView viewMock;
38
Beispiel: Presenter-Test
@Before
public void setup() {
viewMock = Mockito.mock(SearchView.class); //Interface!
requestContextMock = Mockito.mock(DamagedVehicleRequest.class);
presenter = new SearchPresenter(view, request);
}
39
Beispiel: Presenter-Test
@Test
public void testSearchValid() {
Mockito.when(viewMock.getVehicleId()).thenReturn(null);
Mockito.when(requestMock.search(null, null, null))
.thenReturn(requestMock);
presenter.searchOkClicked();
Mockito.verify(requestContextMock)
.search(Mockito.eq((String)null), Mockito.anyString(),
Mockito.anyString());
}
40
Beispiel: Presenter-Test
@Test
public void testSearchInvalid() {
Mockito.when(viewMock.getVehicleId()).thenReturn("1");
presenter.searchOkClicked();
Mockito.verify(viewMock).setErrorText("Fehlermeldung");
Mockito.verifyZeroInteractions(requestContextMock);
}
41
Referenzen
44
Cenarion Techblog – Erfahrungen mit GWT, Tipps & Tricks
http://www.cenarion.com/techblog
View-Tests in GWT: http://www.objectpartners.com/2013/11/07/testing-gwt-
with-gwtmockito/
GWT SDK inkl. einiger Beispielprojekte
http://www.gwtproject.org/download.html
Real-World Projects:
http://www.gwtproject.org/examples.html#real-world-projects
What is the best way to test gwt code:
http://stackoverflow.com/questions/411257/what-is-the-best-way-to-test-gwt-
code
florian.felberbauer@cenarion.com
http://www.cenarion.com/techblog
45

MVP mit dem Google Web Toolkit

  • 1.
    Florian Felberbauer |Cenarion MVP mit dem Google Web Toolkit
  • 2.
  • 3.
  • 4.
  • 5.
    Ablauf • Das Prinzipvon MVP • MVP mit GWT • Activities/Places • Testing 5
  • 6.
    • 1996 vonMike Potel • Verwandt mit MVC • Ziele – Verantwortlichkeiten trennen – Flexibilität von UIs bei Änderungen des Models erhöhen – Testbarkeit der Applikationslogik Model View Presenter 6
  • 7.
  • 8.
    Von MVC zuMVP UI Wie interagieren User mit dem UI? Daten Wie verwalte ich meine Daten? 8
  • 9.
    Daten Wie sehen dieDaten aus? 9 • RDMS • NoSQL • Service • …
  • 10.
    Daten Wie sehen dieDaten aus? Wie werden die Daten spezifiziert? 10 Selektionen der Daten • z.B. Filterung nach ID, Berechtigungen, … • oder Darstellung derselben Daten in versch. Kontext
  • 11.
    Daten Wie sehen dieDaten aus? Wie werden die Daten spezifiziert? Wie werden die Daten modifiziert? 11 • Änderung der Daten auf Selektionen: Insert, Update, …
  • 12.
    UI Wie werden Datendargestellt? 12 • Welche Widgets werden benützt? • Wie sehen versch. Views für versch. Benutzergruppen aus?
  • 13.
    UI Wie werden Datendargestellt? Wie verändern Events die Daten? 13 • Datenänderung durch Events (Klick, Drag&Drop, …)
  • 14.
    UI Wie werden Datendargestellt? Wie verändern Events die Daten? Wie fügt man alles zusammen? 14 = Presenter – Businesslogik verbindet Daten und UI
  • 15.
    Kapselung der Applikationin Client und Server Security 15
  • 16.
    Kapselung der Applikationin Client und Server Security 16 !Client untrustable! Security zumindest auf Serverseite
  • 17.
    Vorteile von MVP •Trennung von Model und View → mehr Flexibilität • Ein Model – mehrere Views • Skalierbarkeit • Testbarkeit 17
  • 18.
    MVP in GWT 18 Server Client Model Presenter View Datenanbindung, Businesstransaktionen UI-Widgets,I18n, Event-Handling, Display-Logik View mit Daten füttern, Applikationslogik
  • 19.
  • 20.
    Warum MVP inGWT? • Arbeitsteilung – Lose Kopplung UI – Logik – Struktur erleichtert Orientierung • Testbarkeit 20
  • 21.
    Warum MVP inGWT? • Arbeitsteilung • Testbarkeit 21
  • 22.
    Warum MVP inGWT? • Arbeitsteilung • Testbarkeit – UI-Komponenten in GWT: • Schwer testbar (GWT-Eigenheiten wie GWT.create()) • Tests langsam 22
  • 23.
    Warum MVP inGWT? • Arbeitsteilung • Testbarkeit – UI-Komponenten in GWT: • Schwer testbar • Tests langsam (HTMLUnit, native JS) 23
  • 24.
    Warum MVP inGWT? • Arbeitsteilung • Testbarkeit – UI-Komponenten in GWT: • Schwer testbar • Tests langsam – Abgrenzung Applikations-Logik von Display-Logik! 24
  • 25.
    Activities & Places •Browser-History • URL-Fragment = Place – .../index.html#SearchPlace!bmw!pkw • Place repräsentiert State • Activity – Kommunikation mit Serverseite – Daten laden & UI initialisieren 25
  • 26.
  • 27.
    Presenter = Activity Presenter (Activity) Place View hältState für initialisiert Model kommuniziert mit 27 aktualisiert
  • 28.
    UiBinder 28 • Trennung Markupund Displaylogik • Reines Markup in XML File • Wird in HTML übersetzt • Code in Java-Klasse • Compile-time checking von Referenzen
  • 29.
  • 30.
    <!DOCTYPE ui:UiBinder SYSTEM"http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <g:Label text="Suche nach beschädigtem Fahrzeug" /> <g:Label text="Fahrgestell-Nr." /> <g:TextBox ui:field="vehicleId" /> <g:Label text="Marke" /> <g:TextBox ui:field="brand" /> <g:Label text="Fahrzeugtyp"/> <g:ListBox ui:field="type" /> <g:Button text="OK“ ui:field="btnOk" /> <g:Button text="Zurücksetzen" /> </ui:UiBinder> 30 Beispiel: SearchViewImpl.ui.xml  <input type="text" … />  <input type="text" … />  <select…><option>…  <input type="button" … />
  • 31.
    <!DOCTYPE ui:UiBinder SYSTEM"http://dl.google.com/gwt/DTD/xhtml.ent"> <ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"> <g:Label text="Suche nach beschädigtem Fahrzeug" /> <g:Label text="Fahrgestell-Nr." /> <g:TextBox ui:field="vehicleId" /> <g:Label text="Marke" /> <g:TextBox ui:field="brand" /> <g:Label text="Fahrzeugtyp"/> <g:ListBox ui:field="type" /> <g:Button text="OK“ ui:field="btnOk" /> <g:Button text="Zurücksetzen" /> <g:Label ui:field="errorText" /> </ui:UiBinder> 31 Beispiel: SearchViewImpl.ui.xml  <input type="text" … />  <input type="text" … />  <select…><option>…  <input type="button" … />
  • 32.
    Beispiel: SearchViewImpl public classSearchViewImpl extends Composite { /** View enthält nur EventHandling, keine Applikationslogik */ @UiField TextBox vehicleId, brand; @UiField ListBox type; @UiField Label errorText; private SearchPresenter presenter; @UiHandler("btnOk") public void onOkClick(ClickEvent event) { presenter.searchOkClicked(); //delegate to presenter } } 32
  • 33.
    Beispiel: Presenter private DamagedVehicleRequestrequest; private SearchView view; public void searchOkClicked() { if (!validVehicleId(view.getVin())) { view.setErrorText("Fehlermeldung"); } else { request.search(view.getVin(), view.getBrand(), view.getType()) .fire(new Receiver …); } } 33
  • 34.
  • 35.
  • 36.
  • 37.
    private DamagedVehicleRequest request; privateSearchView view; public void searchOkClicked() { if (!validVehicleId(view.getVin())) { view.setErrorText("Fehlermeldung"); } else { request.search(view.getVin(), view.getBrand(), view.getType()) .fire(new Receiver …); } } Beispiel: Presenter 37
  • 38.
    Beispiel: Presenter-Test //Mocking derServerkommunikation private final Request<DamagedVehicleProxy> requestMock = mock(Request.class); private DamagedVehicleRequest requestContextMock; private SearchPresenter presenter; //Mocking des View-Interfaces private SearchView viewMock; 38
  • 39.
    Beispiel: Presenter-Test @Before public voidsetup() { viewMock = Mockito.mock(SearchView.class); //Interface! requestContextMock = Mockito.mock(DamagedVehicleRequest.class); presenter = new SearchPresenter(view, request); } 39
  • 40.
    Beispiel: Presenter-Test @Test public voidtestSearchValid() { Mockito.when(viewMock.getVehicleId()).thenReturn(null); Mockito.when(requestMock.search(null, null, null)) .thenReturn(requestMock); presenter.searchOkClicked(); Mockito.verify(requestContextMock) .search(Mockito.eq((String)null), Mockito.anyString(), Mockito.anyString()); } 40
  • 41.
    Beispiel: Presenter-Test @Test public voidtestSearchInvalid() { Mockito.when(viewMock.getVehicleId()).thenReturn("1"); presenter.searchOkClicked(); Mockito.verify(viewMock).setErrorText("Fehlermeldung"); Mockito.verifyZeroInteractions(requestContextMock); } 41
  • 42.
    Referenzen 44 Cenarion Techblog –Erfahrungen mit GWT, Tipps & Tricks http://www.cenarion.com/techblog View-Tests in GWT: http://www.objectpartners.com/2013/11/07/testing-gwt- with-gwtmockito/ GWT SDK inkl. einiger Beispielprojekte http://www.gwtproject.org/download.html Real-World Projects: http://www.gwtproject.org/examples.html#real-world-projects What is the best way to test gwt code: http://stackoverflow.com/questions/411257/what-is-the-best-way-to-test-gwt- code
  • 43.