Test driven java script development

Post on 06-May-2015

1.192 views 3 download

description

JavaScript ist eine sehr dynamische Sprache und verhält sich zudem je nach Browser unterschiedlich. Daher sind automatisierte Tests besonders wertvoll. Dieser Vortrag zeigt, wie Cross-Browser-Tests für JavaScript entwickelt werden können.Vortrag von der MobileTech Conference 2011

Transcript of Test driven java script development

Test-­‐Driven  JavaScript  Development  

Tobias  Bosch  &  Stefan  Scheidt  /  OPITZ  CONSULTING  GmbH  

Wer  sind  wir?  

tobias.bosch@opitz-­‐consulLng.com  (@Lgbro)  

 stefan.scheidt@opitz-­‐consulLng.com  

(@beezlebug)    

© OPITZ CONSULTING GmbH 2011 Seite 3

OPITZ CONSULTING Vorlage Powerpoint 2011; Version 1.3; 10.05.2011; TGA, KSH

1Pager •  Layout ausschließlich für den

1Pager •  Einsatz ist bei Konferenzen,

ext. Veranstaltungen etc. obligatorisch. Die Folie ist Folie 2 (nach der Titelfolie)

•  Der Inhalt darf nicht verändert werden.

•  Ausnahme: Der Block Märkte darf situativ um Partnerlogos (ORACLE, etc.) ergänzt werden

© OPITZ CONSULTING GmbH 2011

Märkte n Java n SOA n ORACLE n BI/DWH n Outtasking

Kunden n Branchen-

übergreifend n Über 600

Kunden

Leistungs- angebot n IT-Strategie n Beratung n Implementierung n Betrieb n Training

Fakten n Gründung 1990 n 400 Mitarbeiter n 8 Standorte in D/

PL

Industrie / Versorger / Telekommunikation

29%

Handel / Logistik / Dienstleistungen 29%

42% Öffentliche Auftraggeber /

Banken & Versicherungen / Vereine & Verbände

Wer  sind  Sie?  

In  diesem  Vortrag  geht‘s  um...    

...automaLsiertes  Testen  ...durch  Entwickler  

Warum  testen?  

Warum  JavaScript-­‐Code  testen?  

Laufzeitumgebungen  für  JavaScript  

          ...  

In  diesem  Vortrag:            

Icon  Set  by  Paul  Irish  (h4p://paulirish.com/2010/high-­‐res-­‐browser-­‐icons/)    

Tests  formulieren  

„Klassisch“  mit  xUnit-­‐Asserts      

„BDD-­‐Style“    à  la  RSpec  

Demo:  BDD  mit  Jasmine  

describe("parseFloat",  function()  {            it("should  return  undefined  for  undefined",  function  ()  {                  expect(util.parseFloat(undefined)).toBeUndefined();          });            it("should  return  0  for  empty  string",  function  ()  {                  expect(util.parseFloat('')).toEqual(0);          });            it("should  return  number  for  number  strings",  function  ()  {                  expect(util.parseFloat('1.5')).toEqual(1.5);          });            //  ...    });  

Hello  Jasmine!  

describe("parseFloat",  function()  {            it("should  return  undefined  for  undefined",  function  ()  {                  expect(util.parseFloat(undefined)).toBeUndefined();          });            it("should  return  0  for  empty  string",  function  ()  {                  expect(util.parseFloat('')).toEqual(0);          });            it("should  return  number  for  number  strings",  function  ()  {                  expect(util.parseFloat('1.5')).toEqual(1.5);          });            //  ...    });  

Hello  Jasmine!  

Suite  

describe("parseFloat",  function()  {            it("should  return  undefined  for  undefined",  function  ()  {                  expect(util.parseFloat(undefined)).toBeUndefined();          });            it("should  return  0  for  empty  string",  function  ()  {                  expect(util.parseFloat('')).toEqual(0);          });            it("should  return  number  for  number  strings",  function  ()  {                  expect(util.parseFloat('1.5')).toEqual(1.5);          });            //  ...    });  

Hello  Jasmine!  

Specs  

describe("parseFloat",  function()  {            it("should  return  undefined  for  undefined",  function  ()  {                  expect(util.parseFloat(undefined)).toBeUndefined();          });            it("should  return  0  for  empty  string",  function  ()  {                  expect(util.parseFloat('')).toEqual(0);          });            it("should  return  number  for  number  strings",  function  ()  {                  expect(util.parseFloat('1.5')).toEqual(1.5);          });            //  ...    });  

Hello  Jasmine!  

Matcher  

Hello  Jasmine!  

expect(x).toEqual(y);  

expect(x).toBe(y);  

expect(x).toBeDefined();  

expect(x).toBeUndefined();  

expect(x).toBeTruthy();  

expect(x).toBeFalsy();  

...  

Matcher  

Hello  Jasmine!  

Spec  Runner  

Fortgeschriaene  Konzepte  

Spies  

Spies  describe("execute  fadein",  function()  {            it("should  eventually  set  opacity  to  1",  function  ()  {                  var  element  =  document.createElement("div");                  spyOn(window,  'setTimeout').andCallFake(                          function(callback)  {                                  callback();                          });                  spyOn(util,  'opacity');                  fadein.execute(element);                  expect(util.opacity.mostRecentCall.args[1]).toEqual(1);          });    });  

Spies  describe("execute  fadein",  function()  {            it("should  eventually  set  opacity  to  1",  function  ()  {                  var  element  =  document.createElement("div");                  spyOn(window,  'setTimeout').andCallFake(                          function(callback)  {                                  callback();                          });                  spyOn(util,  'opacity');                  fadein.execute(element);                  expect(util.opacity.mostRecentCall.args[1]).toEqual(1);          });    });  

Spies  describe("execute  fadein",  function()  {            it("should  eventually  set  opacity  to  1",  function  ()  {                  var  element  =  document.createElement("div");                  spyOn(window,  'setTimeout').andCallFake(                          function(callback)  {                                  callback();                          });                  spyOn(util,  'opacity');                  fadein.execute(element);                  expect(util.opacity.mostRecentCall.args[1]).toEqual(1);          });    });  

Arrange  

Spies  describe("execute  fadein",  function()  {            it("should  eventually  set  opacity  to  1",  function  ()  {                  var  element  =  document.createElement("div");                  spyOn(window,  'setTimeout').andCallFake(                          function(callback)  {                                  callback();                          });                  spyOn(util,  'opacity');                  fadein.execute(element);                  expect(util.opacity.mostRecentCall.args[1]).toEqual(1);          });    });  

//  waits  for  'delay'  seconds  //  then  calls  callback  window.setTimeout  =  function  (callback,  delay)  {          ...  };    

Arrange  

Spies  describe("execute  fadein",  function()  {            it("should  eventually  set  opacity  to  1",  function  ()  {                  var  element  =  document.createElement("div");                  spyOn(window,  'setTimeout').andCallFake(                          function(callback)  {                                  callback();                          });                  spyOn(util,  'opacity');                  fadein.execute(element);                  expect(util.opacity.mostRecentCall.args[1]).toEqual(1);          });    });  

Arrange  //  set  opacity  of  'element'  to  'opacity'  util.opacity  =  function  (element,  opacity)  {          ...  };    

Spies  describe("execute  fadein",  function()  {            it("should  eventually  set  opacity  to  1",  function  ()  {                  var  element  =  document.createElement("div");                  spyOn(window,  'setTimeout').andCallFake(                          function(callback)  {                                  callback();                          });                  spyOn(util,  'opacity');                  fadein.execute(element);                  expect(util.opacity.mostRecentCall.args[1]).toEqual(1);          });    });  

Act  

Spies  

Assert  

describe("execute  fadein",  function()  {            it("should  eventually  set  opacity  to  1",  function  ()  {                  var  element  =  document.createElement("div");                  spyOn(window,  'setTimeout').andCallFake(                          function(callback)  {                                  callback();                          });                  spyOn(util,  'opacity');                  fadein.execute(element);                  expect(util.opacity.mostRecentCall.args[1]).toEqual(1);          });    });  

//  set  opacity  of  'element'  to  'opacity'  util.opacity  =  function  (element,  opacity)  {          ...  };    

FunkLon   Der  Spy  soll...  

spy.andCallThrough()   ...  die  ursprüngliche  FunkLon  aufrufen  

spy.andReturn(argument)   ...  das  übergebene  Argumente  zurückgeben  

spy.andThrow(exception)   ...  die  übergebene  ExcepLon  werfen  

spy.andCallFake(function)   ...  die  übergebene  FunkLon  aufrufen  

FunkLonen  von  Spies  

FunkLon   Prüb,  ob  der  Spy...  

toHaveBeenCalled()   ...  aufrufen  wurde  

toHaveBeenCalledWith(args)   ...  mit  den  übergebenen  Argumenten  aufgerufen  wurde  

Matcher  für  Spies  

FunkLon   Bedeutung  

spy.callCount   Anzahl  der  Aufrufe  

spy.argsForCall[i]   Argumente  des  i-­‐ten  Aufrufs  

spy.mostRecentCall.args   Argumente  des  letzten  Aufrufs  

Eigenschaben  von  Spies  

Asynchrone  Tests  

it("should  eventually  set  opacity  to  1",  function()  {          var  element  =  document.createElement("div");          spyOn(util,  'opacity');          runs(function()  {                  fadein.execute(element);          });          waitsFor(function  ()  {                  return  opacitySpy.mostRecentCall.args[1]  ===  1;          });          runs(function()  {                  //  some  other  expectations                  expect(opacitySpy.mostRecentCall.args[1]).toEqual(1);            });  });  

Asynchrone  Tests  

it("should  eventually  set  opacity  to  1",  function()  {          var  element  =  document.createElement("div");          spyOn(util,  'opacity');          runs(function()  {                  fadein.execute(element);          });          waitsFor(function  ()  {                  return  opacitySpy.mostRecentCall.args[1]  ===  1;          });          runs(function()  {                  //  some  other  expectations                  expect(opacitySpy.mostRecentCall.args[1]).toEqual(1);            });  });  

Asynchrone  Tests  

Arrange  

it("should  eventually  set  opacity  to  1",  function()  {          var  element  =  document.createElement("div");          spyOn(util,  'opacity');          runs(function()  {                  fadein.execute(element);          });          waitsFor(function  ()  {                  return  opacitySpy.mostRecentCall.args[1]  ===  1;          });          runs(function()  {                  //  some  other  expectations                  expect(opacitySpy.mostRecentCall.args[1]).toEqual(1);            });  });  

Asynchrone  Tests  

Act  

it("should  eventually  set  opacity  to  1",  function()  {          var  element  =  document.createElement("div");          spyOn(util,  'opacity');          runs(function()  {                  fadein.execute(element);          });          waitsFor(function  ()  {                  return  opacitySpy.mostRecentCall.args[1]  ===  1;          });          runs(function()  {                  //  some  other  expectations                  expect(opacitySpy.mostRecentCall.args[1]).toEqual(1);            });  });  

Asynchrone  Tests  

Wait...  

//  set  opacity  of  'element'  to  'opacity'  util.opacity  =  function  (element,  opacity)  {          ...  };    

it("should  eventually  set  opacity  to  1",  function()  {          var  element  =  document.createElement("div");          spyOn(util,  'opacity');          runs(function()  {                  fadein.execute(element);          });          waitsFor(function  ()  {                  return  opacitySpy.mostRecentCall.args[1]  ===  1;          });          runs(function()  {                  //  some  other  expectations                  expect(opacitySpy.mostRecentCall.args[1]).toEqual(1);            });  });  

Asynchrone  Tests  

Assert  

UI-­‐Tests  

it("should  fade  in  hello  div  on  button  click",  function  ()  {          var  win,  field,  button;          loadHtml("/js-­‐fadein/index.html");          runs(function()  {                  win  =  testwindow();                  field  =  win.document.getElementById('hello');                  button  =  win.document.getElementById('fadein');          });          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(0);                  jasmine.ui.simulate(button,  'click');          });          waitsForAsync();          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(1);          });  });  

 UI-­‐Test  mit  Jasmine-­‐UI    

it("should  fade  in  hello  div  on  button  click",  function  ()  {          var  win,  field,  button;          loadHtml("/js-­‐fadein/index.html");          runs(function()  {                  win  =  testwindow();                  field  =  win.document.getElementById('hello');                  button  =  win.document.getElementById('fadein');          });          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(0);                  jasmine.ui.simulate(button,  'click');          });          waitsForAsync();          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(1);          });  });  

The  index  pa

ge...  

 UI-­‐Test  mit  Jasmine-­‐UI    

it("should  fade  in  hello  div  on  button  click",  function  ()  {          var  win,  field,  button;          loadHtml("/js-­‐fadein/index.html");          runs(function()  {                  win  =  testwindow();                  field  =  win.document.getElementById('hello');                  button  =  win.document.getElementById('fadein');          });          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(0);                  jasmine.ui.simulate(button,  'click');          });          waitsForAsync();          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(1);          });  });  

Arrange,  Part  1  

 UI-­‐Test  mit  Jasmine-­‐UI    

it("should  fade  in  hello  div  on  button  click",  function  ()  {          var  win,  field,  button;          loadHtml("/js-­‐fadein/index.html");          runs(function()  {                  win  =  testwindow();                  field  =  win.document.getElementById('hello');                  button  =  win.document.getElementById('fadein');          });          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(0);                  jasmine.ui.simulate(button,  'click');          });          waitsForAsync();          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(1);          });  });  

Arrange,  Part  2  

 UI-­‐Test  mit  Jasmine-­‐UI    

it("should  fade  in  hello  div  on  button  click",  function  ()  {          var  win,  field,  button;          loadHtml("/js-­‐fadein/index.html");          runs(function()  {                  win  =  testwindow();                  field  =  win.document.getElementById('hello');                  button  =  win.document.getElementById('fadein');          });          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(0);                  jasmine.ui.simulate(button,  'click');          });          waitsForAsync();          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(1);          });  });  

Act  

 UI-­‐Test  mit  Jasmine-­‐UI    

it("should  fade  in  hello  div  on  button  click",  function  ()  {          var  win,  field,  button;          loadHtml("/js-­‐fadein/index.html");          runs(function()  {                  win  =  testwindow();                  field  =  win.document.getElementById('hello');                  button  =  win.document.getElementById('fadein');          });          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(0);                  jasmine.ui.simulate(button,  'click');          });          waitsForAsync();          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(1);          });  });  

Wait...  

 UI-­‐Test  mit  Jasmine-­‐UI    

it("should  fade  in  hello  div  on  button  click",  function  ()  {          var  win,  field,  button;          loadHtml("/js-­‐fadein/index.html");          runs(function()  {                  win  =  testwindow();                  field  =  win.document.getElementById('hello');                  button  =  win.document.getElementById('fadein');          });          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(0);                  jasmine.ui.simulate(button,  'click');          });          waitsForAsync();          runs(function  ()  {                  expect(win.util.opacity(field)).toEqual(1);          });  });  

Assert  

 UI-­‐Test  mit  Jasmine-­‐UI    

Testausführung  automaLsieren  

Pro   Contra   Beispiele  

Im  Browser  testen  

Laufen  in  ProdukLons-­‐umgebung  

-­‐  Schwerer  zu  automaLsieren  

-­‐  Schwerer  in  CI  einzubeaen  

 QUnit    YUI  Test    Jasmine  

Headless  Browser  

-­‐  Leicht  zu  automaLsieren  

-­‐    Leicht  in  CI  einzubeaen  

Browser  wird  nur  simuliert  

 Envjs  

 PhantomJS    Zombie.js    HtmlUnit  

Browser  fernsteuern  

JsTestDriver  

h4p://code.google.com/p/js-­‐test-­‐driver/  

Demo:  JsTestDriver  

Fazit  

Es  gibt  ein  umfangreiches  Toolset  zum  Testen  von  JavaScript-­‐Code.  

 Testen  Sie  Ihren  Code!  

Testen  Sie  insbesondere  Ihren  JavaScript-­‐Code!  Sie  haben  keine  Ausrede...  

Links  

Jasmine   hap://pivotal.github.com/jasmine/  

Jasmine  UI   haps://github.com/Lgbro/jasmine-­‐ui  

JsTestDriver   hap://code.google.com/p/js-­‐test-­‐driver/  

saturated  wriLng  (By  Eduordo,  hap://www.flickr.com/photos/tnarik/366393127/)  

 Smiley  Keyboard  

(By  ~Prescoa,  hap://www.flickr.com/photos/ppym1/93571524/)    

Spyhole,  Paris  (By  smith  of  smiths,  hap://www.flickr.com/photos/hesketh/232015302/)  

 Sorta  synchronised  diving  

(By  Aaron  Retz,  hap://www.flickr.com/photos/aretz/309469339/)  

Stamp  Collector  (By  C.  CasLllo,  hap://www.flickr.com/photos/carolinedecasLllo/2750577684/)  

 bios  [bible]  

(By  Gastev,  hap://www.flickr.com/photos/gastev/2174505811/)    

Day  276/365:  in  hot  pursuit  (By  Tina  Vega,  hap://www.flickr.com/photos/Lnavega/3066602429/)  

 

Besuchen  Sie  uns  Morgen  beim  Vortrag    

JavaScript  Data  Binding  mit  jQuery  Mobile  

 um  10:00  Uhr  im  Watordsaal  

Vielen  Dank  für  Ihr  Interesse!  

 @Lgbro  

@beezlebug