Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefan Scheidt

2,198 views

Published on

JavaScript ist eine sehr dynamische Sprache und verhält sich zudem je nach Browser unterschiedlich. Daher sind automatisierte Tests besonders wertvoll. Dieser Vortrag von Tobias Bosch und Stefan Scheidt (OPITZ CONSULTING) zeigt, wie Cross-Browser-Tests für JavaScript entwickelt werden können.

Published in: Technology, Business
  • Be the first to comment

Test-driven JavaScript Development - OPITZ CONSULTING - Tobias Bosch - Stefan Scheidt

  1. 1. Tobias Bosch &<br />Stefan Scheidt/ OPITZ CONSULTING GmbH<br />Test-Driven JavaScript Development<br />
  2. 2. Wer sind wir?<br />tobias.bosch@opitz-consulting.com<br />(@tigbro)<br />stefan.scheidt@opitz-consulting.com<br />(@beezlebug)<br />
  3. 3.
  4. 4. Wer sind Sie?<br />
  5. 5. In diesem Vortrag geht‘s um...<br />...automatisiertes Testen<br />...durch Entwickler<br />
  6. 6. Warum testen?<br />
  7. 7. Warum JavaScript-Code testen?<br />
  8. 8. Laufzeitumgebungen für JavaScript<br />...<br />
  9. 9. In diesem Vortrag:<br />Icon Set by Paul Irish (http://paulirish.com/2010/high-res-browser-icons/)<br />
  10. 10. Tests formulieren<br />
  11. 11. „Klassisch“ mit xUnit-Asserts<br />„BDD-Style“ à la RSpec<br />
  12. 12. Demo: BDD mit Jasmine<br />
  13. 13. describe("parseFloat", function() {<br />it("shouldreturnundefinedforundefined", function () {<br />expect(util.parseFloat(undefined)).toBeUndefined();<br /> });<br />it("shouldreturn 0 foremptystring", function () {<br />expect(util.parseFloat('')).toEqual(0);<br /> });<br />it("shouldreturnnumberfornumberstrings", function () {<br />expect(util.parseFloat('1.5')).toEqual(1.5);<br /> });<br /> // ...<br />});<br />Hello Jasmine!<br />
  14. 14. describe("parseFloat", function() {<br />it("shouldreturnundefinedforundefined", function () {<br />expect(util.parseFloat(undefined)).toBeUndefined();<br /> });<br />it("shouldreturn 0 foremptystring", function () {<br />expect(util.parseFloat('')).toEqual(0);<br /> });<br />it("shouldreturnnumberfornumberstrings", function () {<br />expect(util.parseFloat('1.5')).toEqual(1.5);<br /> });<br /> // ...<br />});<br />Hello Jasmine!<br />Suite<br />
  15. 15. describe("parseFloat", function() {<br />it("shouldreturnundefinedforundefined", function () {<br />expect(util.parseFloat(undefined)).toBeUndefined();<br />});<br />it("shouldreturn 0 foremptystring", function () {<br />expect(util.parseFloat('')).toEqual(0);<br /> });<br />it("shouldreturnnumberfornumberstrings", function () {<br />expect(util.parseFloat('1.5')).toEqual(1.5);<br /> });<br /> // ...<br />});<br />Hello Jasmine!<br />Specs<br />
  16. 16. describe("parseFloat", function() {<br />it("shouldreturnundefinedforundefined", function () {<br />expect(util.parseFloat(undefined)).toBeUndefined();<br /> });<br />it("shouldreturn 0 foremptystring", function () {<br />expect(util.parseFloat('')).toEqual(0);<br /> });<br />it("shouldreturnnumberfornumberstrings", function () {<br />expect(util.parseFloat('1.5')).toEqual(1.5);<br /> });<br /> // ...<br />});<br />Hello Jasmine!<br />Matcher<br />
  17. 17. Hello Jasmine!<br />expect(x).toEqual(y);<br />expect(x).toBe(y);<br />expect(x).toBeDefined();<br />expect(x).toBeUndefined();<br />expect(x).toBeTruthy();<br />expect(x).toBeFalsy();<br />...<br />Matcher<br />
  18. 18. Hello Jasmine!<br />Spec Runner<br />
  19. 19. Fortgeschrittene Konzepte<br />
  20. 20. Spies<br />
  21. 21. Spies<br />describe("execute fadein", function() {<br /> it("should eventually set opacity to 1", function () {<br />varelement = document.createElement("div");<br />spyOn(window, 'setTimeout').andCallFake(<br /> function(callback) {<br /> callback();<br /> });<br />spyOn(util, 'opacity');<br />fadein.execute(element);<br /> expect(util.opacity.mostRecentCall.args[1]).toEqual(1);<br /> });<br />});<br />
  22. 22. Spies<br />describe("execute fadein", function() {<br /> it("should eventually set opacity to 1", function () {<br />varelement = document.createElement("div");<br />spyOn(window, 'setTimeout').andCallFake(<br /> function(callback) {<br /> callback();<br /> });<br />spyOn(util, 'opacity');<br />fadein.execute(element);<br /> expect(util.opacity.mostRecentCall.args[1]).toEqual(1);<br /> });<br />});<br />
  23. 23. Spies<br />describe("execute fadein", function() {<br /> it("should eventually set opacity to 1", function () {<br />varelement = document.createElement("div");<br />spyOn(window, 'setTimeout').andCallFake(<br /> function(callback) {<br /> callback();<br /> });<br />spyOn(util, 'opacity');<br />fadein.execute(element);<br /> expect(util.opacity.mostRecentCall.args[1]).toEqual(1);<br /> });<br />});<br />Arrange<br />
  24. 24. Spies<br />describe("execute fadein", function() {<br /> it("should eventually set opacity to 1", function () {<br />varelement = document.createElement("div");<br />spyOn(window, 'setTimeout').andCallFake(<br /> function(callback) {<br /> callback();<br /> });<br />spyOn(util, 'opacity');<br />fadein.execute(element);<br /> expect(util.opacity.mostRecentCall.args[1]).toEqual(1);<br /> });<br />});<br />Arrange<br />// waitsfor 'delay' seconds<br />// thencallscallback<br />window.setTimeout = function (callback, delay) {<br /> ...<br />}; <br />
  25. 25. Spies<br />describe("execute fadein", function() {<br /> it("should eventually set opacity to 1", function () {<br />varelement = document.createElement("div");<br />spyOn(window, 'setTimeout').andCallFake(<br /> function(callback) {<br /> callback();<br /> });<br />spyOn(util, 'opacity');<br />fadein.execute(element);<br /> expect(util.opacity.mostRecentCall.args[1]).toEqual(1);<br /> });<br />});<br />Arrange<br />// setopacityof 'element' to 'opacity'<br />util.opacity = function (element, opacity) {<br /> ...<br />}; <br />
  26. 26. Spies<br />describe("execute fadein", function() {<br /> it("should eventually set opacity to 1", function () {<br />varelement = document.createElement("div");<br />spyOn(window, 'setTimeout').andCallFake(<br /> function(callback) {<br /> callback();<br /> });<br />spyOn(util, 'opacity');<br />fadein.execute(element);<br /> expect(util.opacity.mostRecentCall.args[1]).toEqual(1);<br /> });<br />});<br />Act<br />
  27. 27. Spies<br />describe("execute fadein", function() {<br /> it("should eventually set opacity to 1", function () {<br />varelement = document.createElement("div");<br />spyOn(window, 'setTimeout').andCallFake(<br /> function(callback) {<br /> callback();<br /> });<br />spyOn(util, 'opacity');<br />fadein.execute(element);<br /> expect(util.opacity.mostRecentCall.args[1]).toEqual(1);<br /> });<br />});<br />// setopacityof 'element' to 'opacity'<br />util.opacity = function (element, opacity) {<br /> ...<br />}; <br />Assert<br />
  28. 28. Funktionen von Spies<br />
  29. 29. Matcher für Spies<br />Eigenschaften von Spies<br />
  30. 30. Asynchrone Tests<br />
  31. 31. it("should eventually set opacity to 1", function() {<br />var element = document.createElement("div");<br />spyOn(util, 'opacity');<br /> runs(function() {<br />fadein.execute(element);<br />});<br />waitsFor(function () {<br /> return opacitySpy.mostRecentCall.args[1] === 1;<br />});<br />runs(function() {<br /> // some other expectations<br /> expect(opacitySpy.mostRecentCall.args[1]).toEqual(1); <br /> });<br />});<br />Asynchrone Tests<br />
  32. 32. it("should eventually set opacity to 1", function() {<br />var element = document.createElement("div");<br />spyOn(util, 'opacity');<br /> runs(function() {<br />fadein.execute(element);<br />});<br />waitsFor(function () {<br /> return opacitySpy.mostRecentCall.args[1] === 1;<br />});<br />runs(function() {<br /> // some other expectations<br /> expect(opacitySpy.mostRecentCall.args[1]).toEqual(1); <br /> });<br />});<br />Asynchrone Tests<br />Arrange<br />
  33. 33. it("should eventually set opacity to 1", function() {<br />var element = document.createElement("div");<br />spyOn(util, 'opacity');<br /> runs(function() {<br />fadein.execute(element);<br />});<br />waitsFor(function () {<br /> return opacitySpy.mostRecentCall.args[1] === 1;<br />});<br />runs(function() {<br /> // some other expectations<br /> expect(opacitySpy.mostRecentCall.args[1]).toEqual(1); <br /> });<br />});<br />Asynchrone Tests<br />Act<br />
  34. 34. it("should eventually set opacity to 1", function() {<br />var element = document.createElement("div");<br />spyOn(util, 'opacity');<br /> runs(function() {<br />fadein.execute(element);<br />});<br />waitsFor(function () {<br /> return opacitySpy.mostRecentCall.args[1] === 1;<br />});<br />runs(function() {<br /> // some other expectations<br /> expect(opacitySpy.mostRecentCall.args[1]).toEqual(1); <br /> });<br />});<br />Asynchrone Tests<br />Wait...<br />// setopacityof 'element' to 'opacity'<br />util.opacity = function (element, opacity) {<br /> ...<br />}; <br />
  35. 35. it("should eventually set opacity to 1", function() {<br />var element = document.createElement("div");<br />spyOn(util, 'opacity');<br /> runs(function() {<br />fadein.execute(element);<br />});<br />waitsFor(function () {<br /> return opacitySpy.mostRecentCall.args[1] === 1;<br />});<br />runs(function() {<br /> // some other expectations<br /> expect(opacitySpy.mostRecentCall.args[1]).toEqual(1); <br /> });<br />});<br />Asynchrone Tests<br />Assert<br />
  36. 36. UI-Tests<br />
  37. 37.
  38. 38. it("should fade in hello div on buttonclick", function () {<br />varwin, field, button;<br />loadHtml("/js-fadein/index.html");<br />runs(function() {<br />win = testwindow();<br />field = win.document.getElementById('hello');<br />button = win.document.getElementById('fadein');<br /> });<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(0);<br />jasmine.ui.simulate(button, 'click');<br /> });<br />waitsForAsync();<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(1);<br /> });<br />});<br />UI-Test mit Jasmine-UI<br />
  39. 39. it("should fade in hello div on buttonclick", function () {<br />varwin, field, button;<br />loadHtml("/js-fadein/index.html");<br />runs(function() {<br />win = testwindow();<br />field = win.document.getElementById('hello');<br />button = win.document.getElementById('fadein');<br /> });<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(0);<br />jasmine.ui.simulate(button, 'click');<br /> });<br />waitsForAsync();<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(1);<br /> });<br />});<br />The indexpage...<br />UI-Test mit Jasmine-UI<br />
  40. 40. it("should fade in hello div on buttonclick", function () {<br />varwin, field, button;<br />loadHtml("/js-fadein/index.html");<br />runs(function() {<br />win = testwindow();<br />field = win.document.getElementById('hello');<br />button = win.document.getElementById('fadein');<br /> });<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(0);<br />jasmine.ui.simulate(button, 'click');<br /> });<br />waitsForAsync();<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(1);<br /> });<br />});<br />Arrange, Part 1<br />UI-Test mit Jasmine-UI<br />
  41. 41. it("should fade in hello div on buttonclick", function () {<br />varwin, field, button;<br />loadHtml("/js-fadein/index.html");<br />runs(function() {<br />win = testwindow();<br />field = win.document.getElementById('hello');<br />button = win.document.getElementById('fadein');<br /> });<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(0);<br />jasmine.ui.simulate(button, 'click');<br /> });<br />waitsForAsync();<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(1);<br /> });<br />});<br />Arrange, Part 2<br />UI-Test mit Jasmine-UI<br />
  42. 42. it("should fade in hello div on buttonclick", function () {<br />varwin, field, button;<br />loadHtml("/js-fadein/index.html");<br />runs(function() {<br />win = testwindow();<br />field = win.document.getElementById('hello');<br />button = win.document.getElementById('fadein');<br /> });<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(0);<br />jasmine.ui.simulate(button, 'click');<br /> });<br />waitsForAsync();<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(1);<br /> });<br />});<br />Act<br />UI-Test mit Jasmine-UI<br />
  43. 43. it("should fade in hello div on buttonclick", function () {<br />varwin, field, button;<br />loadHtml("/js-fadein/index.html");<br />runs(function() {<br />win = testwindow();<br />field = win.document.getElementById('hello');<br />button = win.document.getElementById('fadein');<br /> });<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(0);<br />jasmine.ui.simulate(button, 'click');<br /> });<br />waitsForAsync();<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(1);<br /> });<br />});<br />Wait...<br />UI-Test mit Jasmine-UI<br />
  44. 44. it("should fade in hello div on buttonclick", function () {<br />varwin, field, button;<br />loadHtml("/js-fadein/index.html");<br />runs(function() {<br />win = testwindow();<br />field = win.document.getElementById('hello');<br />button = win.document.getElementById('fadein');<br /> });<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(0);<br />jasmine.ui.simulate(button, 'click');<br /> });<br />waitsForAsync();<br />runs(function () {<br />expect(win.util.opacity(field)).toEqual(1);<br /> });<br />});<br />Assert<br />UI-Test mit Jasmine-UI<br />
  45. 45. Testausführung automatisieren<br />
  46. 46.
  47. 47. Browser fernsteuern<br />
  48. 48. JsTestDriver<br />http://code.google.com/p/js-test-driver/<br />
  49. 49. Demo: JsTestDriver<br />
  50. 50. Fazit<br />Es gibt ein umfangreiches Toolset zum Testen von JavaScript-Code.<br />Testen Sie Ihren Code!<br />Testen Sie insbesondere Ihren JavaScript-Code!<br />Sie haben keine Ausrede...<br />
  51. 51. Links<br />
  52. 52. saturatedwriting<br />(ByEduordo, http://www.flickr.com/photos/tnarik/366393127/)<br />Smiley Keyboard<br />(By~Prescott, http://www.flickr.com/photos/ppym1/93571524/)<br />Spyhole, Paris<br />(Bysmithofsmiths, http://www.flickr.com/photos/hesketh/232015302/)<br />Sortasynchroniseddiving<br />(By Aaron Retz, http://www.flickr.com/photos/aretz/309469339/)<br />
  53. 53. StampCollector<br />(ByC. Castillo, http://www.flickr.com/photos/carolinedecastillo/2750577684/)<br />bios[bible]<br />(ByGastev, http://www.flickr.com/photos/gastev/2174505811/)<br />Day 276/365: in hotpursuit<br />(By Tina Vega, http://www.flickr.com/photos/tinavega/3066602429/)<br />
  54. 54. Vielen Dankfür Ihr Interesse!@tigbro@beezlebug<br />

×