About Me
Questo non riguarda la
tecnologia
Ma se non c’e’ tecnologia poi
mi dicono che il tdd e’ solo per
il dominio
Il Gioco
• Si chiama “Boss”, e’ una specie di GTA su
browser
– Il giocatore ha una vista a volo d’uccello sulla città
e su...
Il Primo Test
Il Primo Test
public class BossBehavior {
@Test
public void shouldAnswerHttpCall() throws IOException {
new Boss(8080);
We...
La Soluzione
public class Boss {
public Boss(int port) throws IOException {
SelectorThread selector = new SelectorThread()...
Un po’ di refactoring
@Test
public void shouldAnswerHttpCall() throws Exception {
new Boss(PORT);
assertThat(Http.callOn(P...
• Se non posso parlare di un’entità non posso farne
il design
• Per fare il design di un sistema ho bisogno di “new
Sistem...
Il Secondo Test
Il Secondo Test
@Test
public void shouldAnswerWithAnHtmlDocument() throws Exception {
new Boss(PORT);
assertThat(Http.call...
Tutto verde?
@Test
public void shouldAnswerWithAnHtmlDocument() {
new Boss(PORT);
assertThat(Http.callOn(PORT),
is(HttpAns...
Sfruttare le microdivergenze
Il concetto di Screen nasce per conciliare due tests
@Test
public void shouldAnswerHttpCall()...
La Nascita Della Gui
Il Movimento Verso il Basso
public class HtmlScreenBehavior {
@Test
public void shouldRenderAnHtmlDoc...
Un Edificio
La grafica vettoriale secondo Raphael
<html>
<head>
<script type="text/javascript" src="raphael-min.js"></scri...
Testare un sacco di sintassi?
@Test
public void shouldRenderABuildingAsARectangle() {
assertThat(new HtmlScreen().render()...
O dichiarare il comportamento?
@Test
public void shouldRenderABuildingAsARectangle() throws Exception {
User user = new Us...
Si, bello, ma come?
function Raphael(x, y, width, height){
this.rect = function(x, y, width, height) {
output = "A Rectang...
Ma chi e’ ‘sto User?
public class User {
…
public User lookAt(String htmlPage) {
JavaScriptSource source = new XomJavaScri...
Il risultato
public class HtmlScreen implements Screen {
private Building building = new Building(10, 10, 40, 50);
public ...
Mantenere sempre l’omogeneità
public class HtmlScreen {
...
public String render() {
return header() +
vectorGraphics.incl...
Tanti Edifici!
@Test
public void shouldRenderMultipleBuildings() throws Exception {
HtmlScreen htmlScreen = new HtmlScreen...
Il Personaggio
@Test
public void shouldRenderACharacter() {
HtmlScreen htmlScreen = new HtmlScreen().addCharacter(70,60);
...
Generalizzazione
private String renderViewElements() {
String renderedElements = "";
for (ViewElement element : viewElemen...
Un’ultima volta verso il basso
@Test
public void shouldBeARedCircle() {
GameCharacter character = new GameCharacter(10,10)...
Questo non riguarda solo la vista
Un’occhiata al futuro di questa applicazione…
Interazione :
@Test
public void characterS...
Questo non riguarda solo la vista
Avendo le buone primitive ogni asserzione e’ possibile…
Arriva la persistenza :
@Test
pu...
Grazie!
TDD per Webapps
Upcoming SlideShare
Loading in …5
×

TDD per Webapps

925 views

Published on

My way of applying TDD to web-applications development (and to any other kind of application actually).

Italian version.

Published in: Technology, Business
1 Comment
1 Like
Statistics
Notes
  • Veramente interessante: conto di vedere presto anche il talk registrato che all'AgileDay non sono riuscito a seguire
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
925
On SlideShare
0
From Embeds
0
Number of Embeds
396
Actions
Shares
0
Downloads
13
Comments
1
Likes
1
Embeds 0
No embeds

No notes for slide

TDD per Webapps

  1. 1. About Me
  2. 2. Questo non riguarda la tecnologia Ma se non c’e’ tecnologia poi mi dicono che il tdd e’ solo per il dominio
  3. 3. Il Gioco • Si chiama “Boss”, e’ una specie di GTA su browser – Il giocatore ha una vista a volo d’uccello sulla città e sul personaggio – Quando il giocatore clicca sulla mappa il personaggio si sposta – Il giocatore vede gli altri personaggi sulla mappa – ….
  4. 4. Il Primo Test
  5. 5. Il Primo Test public class BossBehavior { @Test public void shouldAnswerHttpCall() throws IOException { new Boss(8080); WebClient client = new WebClient(); Page page = client.getPage("http://localhost:8080"); assertThat(page.getWebResponse().getStatusCode(), is(200)); } }
  6. 6. La Soluzione public class Boss { public Boss(int port) throws IOException { SelectorThread selector = new SelectorThread(); selector.setPort(port); selector.setAdapter(new AlwaysReturn200Ok()); selector.listen(); } }
  7. 7. Un po’ di refactoring @Test public void shouldAnswerHttpCall() throws Exception { new Boss(PORT); assertThat(Http.callOn(PORT), is(OK)); }
  8. 8. • Se non posso parlare di un’entità non posso farne il design • Per fare il design di un sistema ho bisogno di “new Sistema()” • Quindi, l’application server, se c’e’, deve essere un dettaglio implementativo
  9. 9. Il Secondo Test
  10. 10. Il Secondo Test @Test public void shouldAnswerWithAnHtmlDocument() throws Exception { new Boss(PORT); assertThat(Http.callOn(PORT), is(HttpAnswer.with("<html><body></body></html>"))); } public class Boss { ... public Boss(int port) throws IOException, InstantiationException { selector = new SelectorThread(); selector.setPort(port); HttpAnswer answer = HttpAnswer.with("<html><body></body></html>"); selector.setAdapter(new AlwaysReturn(answer)); selector.listen(); } ... }
  11. 11. Tutto verde? @Test public void shouldAnswerWithAnHtmlDocument() { new Boss(PORT); assertThat(Http.callOn(PORT), is(HttpAnswer.with("<html><body></body></html>"))); } @Test public void shouldAnswerHttpCall() { new Boss(PORT); assertThat(Http.callOn(PORT), is(OK)); }
  12. 12. Sfruttare le microdivergenze Il concetto di Screen nasce per conciliare due tests @Test public void shouldAnswerHttpCall() throws Exception { Boss boss = new Boss(PORT, new BlankScreen()); HttpAnswer answer = Http.callOn(PORT); boss.stop(); assertThat(answer, is(HttpAnswer.ok())); } @Test public void shouldAnswerWithAnHtmlDocument() throws Exception { Boss boss = new Boss(PORT, new HtmlScreen()); HttpAnswer answer = Http.callOn(PORT); boss.stop(); assertThat(answer, is(HttpAnswer.with("<html><body></body></html>"))); }
  13. 13. La Nascita Della Gui Il Movimento Verso il Basso public class HtmlScreenBehavior { @Test public void shouldRenderAnHtmlDocument() { assertThat(new HtmlScreen().render(), is("<html><body></body></html>")); } } L’Asserzione a Specchio @Test public void shouldAnswerWithTheScreenContents() throws Exception { Screen screen = new HtmlScreen(); boss = new Boss(PORT, screen); assertThat(Http.callOn(PORT), is(HttpAnswer.with(screen.render()))); }
  14. 14. Un Edificio La grafica vettoriale secondo Raphael <html> <head> <script type="text/javascript" src="raphael-min.js"></script> <script type="text/javascript" charset="utf-8"> window.onload = function() { var map = new Raphael(0,0,600,400); map.rect(10,10,50,40); }; </script> </head> <body> </body> </html>
  15. 15. Testare un sacco di sintassi? @Test public void shouldRenderABuildingAsARectangle() { assertThat(new HtmlScreen().render(), is("<html>n" + "<head>n" + " <script type="text/javascript" src="raphael-min.js"></script>n" + " <script type="text/javascript" charset="utf-8">n" + " window.onload = function() {n" + " var map = new Raphael(0,0,600,400);n" + " var building = map.rect(10,10,50,40);n" + " };n" + " </script>n" + "</head>n" + "<body>n" + "</body>n" + "</html>")); }
  16. 16. O dichiarare il comportamento? @Test public void shouldRenderABuildingAsARectangle() throws Exception { User user = new User().lookAt(new HtmlScreen().render()); assertThat(user.currentSight(), is("A Rectangle at [10,10], 40px high and 50px wide")); } Cosa voglio veramente dichiarare?
  17. 17. Si, bello, ma come? function Raphael(x, y, width, height){ this.rect = function(x, y, width, height) { output = "A Rectangle at [" + x + "," + y + "], " + height + "px high and " + width + "px wide"; } } var output = “”; Come stubbare una libreria di grafica vettoriale? function Window() { } var window = new Window(); Come stubbare un browser?
  18. 18. Ma chi e’ ‘sto User? public class User { … public User lookAt(String htmlPage) { JavaScriptSource source = new XomJavaScriptSource(htmlPage); source.evaluateWith(javaScript); triggerOnLoad(); result.readOutput(javaScript); return this; } … }
  19. 19. Il risultato public class HtmlScreen implements Screen { private Building building = new Building(10, 10, 40, 50); public String render() { String start = "<html><head>" + " <script type="text/javascript" src="raphael-min.js"></script>" + " <script type="text/javascript" charset="utf-8">" + " window.onload = function() {" + " var map = new Raphael(0,0,600,400);"; String end = "}</script></head><body></body></html>"; return start + building.render() + end; }
  20. 20. Mantenere sempre l’omogeneità public class HtmlScreen { ... public String render() { return header() + vectorGraphics.include() + openScript() + openFunction() + vectorGraphics.init() + building.render(vectorGraphics) + closeFunction() + closeScript() + ending(); } ... }
  21. 21. Tanti Edifici! @Test public void shouldRenderMultipleBuildings() throws Exception { HtmlScreen htmlScreen = new HtmlScreen(); htmlScreen.addBuilding(10,10,50,40); htmlScreen.addBuilding(80,10,30,40); htmlScreen.addBuilding(10,70,100,40); User user = new User().lookAt(htmlScreen.render()); assertThat(user.currentSight(), is(aRectangle(10, 10, 50, 40))); assertThat(user.currentSight(), is(aRectangle(80, 10, 30, 40))); assertThat(user.currentSight(), is(aRectangle(10, 70, 100, 40))); }
  22. 22. Il Personaggio @Test public void shouldRenderACharacter() { HtmlScreen htmlScreen = new HtmlScreen().addCharacter(70,60); User user = new User().lookAt(htmlScreen.render()); assertThat(user.currentSight(), is(aCircle(70, 60, 5))); }
  23. 23. Generalizzazione private String renderViewElements() { String renderedElements = ""; for (ViewElement element : viewElements) { renderedElements += element.render(vectorGraphics); } return renderedElements; } L’HtmlScreen smette di parlare di buildings e characters public HtmlScreen addViewElement(ViewElement element) { viewElements.add(element); return this; }
  24. 24. Un’ultima volta verso il basso @Test public void shouldBeARedCircle() { GameCharacter character = new GameCharacter(10,10); VectorGraphics vectorGraphics = new TextualVectorGraphics(); assertThat(character.render(vectorGraphics), is("A Circle at [10,10], 5px in diameter")); } public class TextualVectorGraphics implements VectorGraphics { @Override public String rect(int x, int y, int width, int height) { return aRectangle(x,y,width,height); } @Override public String circle(int x, int y, int size) { return aCircle(x,y,size); } }
  25. 25. Questo non riguarda solo la vista Un’occhiata al futuro di questa applicazione… Interazione : @Test public void characterShouldMoveOnClick() { String page = Http.callOn(PORT).payload(); user.lookAt(page); user.clickOn(60, 60); page = Http.callOn(PORT).payload(); user.lookAt(page); assertThat(user.currentSight, is("A Circle at [60,60], 5px in diameter")); } Il protocollo si stacca dalla logica del gioco : @Test public void shouldAnswerHttpCall() throws Exception { httpServer = new HttpServer(PORT).publish(boss); assertThat(Http.callOn(PORT), is(HttpAnswer.ok())); }
  26. 26. Questo non riguarda solo la vista Avendo le buone primitive ogni asserzione e’ possibile… Arriva la persistenza : @Test public void characterPositionShouldPersist() { Boss boss1 = new Boss(persistence, screen1); boss1.moveCharacterTo(30,30); Boss boss2 = new Boss(persistence, screen2); assertThat(screen2.render(), is("A Circle at [30,30], 5px in diameter")); } Ajax : @Test public void characterShouldMoveOnClick() { page = new HtmlScreen().render(); user.lookAt(page); user.clickOn(60, 60); assertThat(user.currentSight, is("A Circle at [60,60], 5px in diameter")); }
  27. 27. Grazie!

×