SlideShare une entreprise Scribd logo
1  sur  61
Test Driven JavaScript Development


Tobias Bosch
OPITZ CONSULTING Deutschland GmbH
Who am I?



tobias.bosch@opitz-consulting.com
            (@tigbro)
Mission                                                                  Markets
The company's ambition is to help                                         Branchspreading
organizations to be better than their                                     Over 600 customers
competitors.                                                                                                  29%
                                                                                                              Trade / Logistics /
Our services take place in partnership and                                                29%                 Supplier
                                                                          Industry / Services /
are aimed at a co-operation of many years.                               Telecommunications

                                                                                                      42%
                                                                                                      Public Clients / Banks and Insurance
                                                                                                      Associations and Federations



Portfolio                                                                Basic Data
 Business IT Alignment                                                   Founded in 1990
 Business Information Management                                         400 employees
 Business Process Management                                             8 offices
 Application Development
 SOA and System Integration
 IT Infrastructure Management


                   <Präsentationstitel – bitte im Folienmaster ändern>                            © OPITZ CONSULTING GmbH 2011           Seite 3
Who are you?
This talk is about...

    ... automatic tests
... written by developers
Why should I test?
Why should I test JavaScript code?
Runtime environments for
       JavaScript




                       ...
In this talk




Icon Set by Paul Irish (http://paulirish.com/2010/high-res-browser-icons/)
The example
Writing tests
„Classic style“ with
    xUnit asserts

„BDD style“ à la RSpec
Demo: BDD with Jasmine
Hello Jasmine!

  expect(x).toEqual(y);
    expect(x).toBe(y);
 expect(x).toBeDefined();
expect(x).toBeUndefined();
 expect(x).toBeTruthy();
  expect(x).toBeFalsy();
           ...
Advanced concepts
Spies
Spies
describe("execute fadein", function() {
    it("should eventually set opacity to 1", function () {
        var element = document.createElement("div");
        jasmine.Clock.useMock();
        spyOn(util, 'opacity');
        fadein.execute(element);
        jasmine.Clock.tick(1000);
        var mostRecentCall = util.opacity.mostRecentCall;
        expect(mostRecentCall.args[0]).toBe(element);
        expect(mostRecentCall.args[1]).toEqual(1);
    });
});
Spies
describe("execute fadein", function() {
    it("should eventually set opacity to 1", function () {
        var element = document.createElement("div");
        jasmine.Clock.useMock();
        spyOn(util, 'opacity');
        fadein.execute(element);
        jasmine.Clock.tick(1000);
        var mostRecentCall = util.opacity.mostRecentCall;
        expect(mostRecentCall.args[0]).toBe(element);
        expect(mostRecentCall.args[1]).toEqual(1);
    });
});
Spies
describe("execute fadein", function() {
    it("should eventually set opacity to 1", function () {
        var element = document.createElement("div");
        jasmine.Clock.useMock();
        spyOn(util, 'opacity');
        fadein.execute(element);
        jasmine.Clock.tick(1000);
        var mostRecentCall = util.opacity.mostRecentCall;
        expect(mostRecentCall.args[0]).toBe(element);
        expect(mostRecentCall.args[1]).toEqual(1);
    });
});
Spies
describe("execute fadein", function() {
    it("should eventually set opacity to 1", function () {
        var element = document.createElement("div");
        jasmine.Clock.useMock();
        spyOn(util, 'opacity');
        fadein.execute(element);
        jasmine.Clock.tick(1000);
        var mostRecentCall = util.opacity.mostRecentCall;
        expect(mostRecentCall.args[0]).toBe(element);
        expect(mostRecentCall.args[1]).toEqual(1);
    });
});
Spies
describe("execute fadein", function() {
    it("should eventually set opacity to 1", function () {
        var element = document.createElement("div");
        jasmine.Clock.useMock();
        spyOn(util, 'opacity');
        fadein.execute(element);
        jasmine.Clock.tick(1000);of 'element' to 'opacity'
                  // set opacity
        var mostRecentCall = util.opacity.mostRecentCall;
                  util.opacity = function (element, opacity) {
                      ...
        expect(mostRecentCall.args[0]).toBe(element);
                  };
        expect(mostRecentCall.args[1]).toEqual(1);
      });
});
Spies
describe("execute fadein", function() {
    it("should eventually set opacity to 1", function () {
        var element = document.createElement("div");
        jasmine.Clock.useMock();
        spyOn(util, 'opacity');
        fadein.execute(element);
        jasmine.Clock.tick(1000);
        var mostRecentCall = util.opacity.mostRecentCall;
        expect(mostRecentCall.args[0]).toBe(element);
        expect(mostRecentCall.args[1]).toEqual(1);
    });
});
Spies
describe("execute fadein", function() {
    it("should eventually set opacity to 1", function () {
        var element = document.createElement("div");
        jasmine.Clock.useMock();
        spyOn(util, 'opacity');
        fadein.execute(element);
        jasmine.Clock.tick(1000);
        var mostRecentCall = util.opacity.mostRecentCall;
        expect(mostRecentCall.args[0]).toBe(element);
        expect(mostRecentCall.args[1]).toEqual(1);
    });
});
Spies
describe("execute fadein", function() {
    it("should eventually set opacity to 1", function () {
        var element = document.createElement("div");
        jasmine.Clock.useMock();
        spyOn(util, 'opacity');
        fadein.execute(element);
        jasmine.Clock.tick(1000);
        var mostRecentCall = util.opacity.mostRecentCall;
        expect(mostRecentCall.args[0]).toBe(element);
        expect(mostRecentCall.args[1]).toEqual(1);
    });
});
Spies
describe("execute fadein", function() {
    it("should eventually set opacity to 1", function () {
                 // set opacity of 'element' to 'opacity'
                 util.opacity = function (element, opacity) {
        var element = document.createElement("div");
                     ...
        jasmine.Clock.useMock();
                 };
        spyOn(util, 'opacity');
        fadein.execute(element);
        jasmine.Clock.tick(1000);
        var mostRecentCall = util.opacity.mostRecentCall;
        expect(mostRecentCall.args[0]).toBe(element);
        expect(mostRecentCall.args[1]).toEqual(1);
    });
});
Function                    The spy should...

spy.andCallThrough()        ... call the original function

spy.andReturn(argument)     ... return the given argument

spy.andThrow(exception)     ... throw the given exception

spy.andCallFake(function)   ... call the given function


                Functions of spies
Function                      Checks whether the spy...
toHaveBeenCalled()            ... has been called
                              ... has been called with the given
toHaveBeenCalledWith(args)
                                  arguments
                     Matcher for spies


Function                      Description
spy.callCount                 Number of calls

spy.argsForCall[i]            Arguments of the i-th call

spy.mostRecentCall.args       Arguments of the last call

                     Properties of spies
Asynchronous tests
Asynchronous 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);
    });
});
Asynchronous 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);
    });
});
Asynchronous 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);
    });
});
Asynchronous 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
                  // set opacity of 'element' to 'opacity'
        expect(opacitySpy.mostRecentCall.args[1]).toEqual(1); {
                  util.opacity = function (element, opacity)
    });               ...
});               };
Asynchronous 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);
    });
});
UI tests with Jasmine UI
Jasmine UI

  Extension of JS test framework Jasmine

Allows to load, instrument and test a webapp
                in the browser

  Supports testing asynchronous behaviour
Analyse             HTML Session Storage   Show
            specs                                    results


    Scripts:                     Load                          Scripts:
                                 app
jasmine-ui.js                                            jasmine-ui.js
jasmine-html.js                                          jasmine-html.js
"uiSpec.js"                             Collect          "uiSpec.js"
                                        results

UiSpecRunner.html                                       UiSpecRunner.html
                                   Scripts:

                               "app.js"
                    Execute    "uiSpec.js"
                      specs
                                  index.html
<html>
<body>

<div id="hello">Hello World!</div>

<button id="fadein">Fade in</button>

</body>
</html>




                                       UI tests with Jasmine-UI
describeUi("index", "/js-fadein/index.html", function () {

      it("should fade in hello div on button click", function () {
          var win, field, button;
          runs(function() {
              field = document.getElementById('hello');
              button = document.getElementById('fadein');
              expect(util.opacity(field)).toEqual(0);
              simulate(button, 'click');
          });
          runs(function () {
              expect(util.opacity(field)).toEqual(1);
          });
      });

});

                                               UI tests with Jasmine-UI
describeUi("index", "/js-fadein/index.html", function () {

      it("should fade in hello div on button click", function () {
          var win, field, button;
          runs(function() {
              field = document.getElementById('hello');
              button = document.getElementById('fadein');
              expect(util.opacity(field)).toEqual(0);
              simulate(button, 'click');
          });
          runs(function () {
              expect(util.opacity(field)).toEqual(1);
          });
      });

});

                                               UI tests with Jasmine-UI
describeUi("index", "/js-fadein/index.html", function () {

      it("should fade in hello div on button click", function () {
          var win, field, button;
          runs(function() {
              field = document.getElementById('hello');
              button = document.getElementById('fadein');
              expect(util.opacity(field)).toEqual(0);
              simulate(button, 'click');
          });
          runs(function () {
              expect(util.opacity(field)).toEqual(1);
          });
      });

});

                                               UI tests with Jasmine-UI
describeUi("index", "/js-fadein/index.html", function () {

      it("should fade in hello div on button click", function () {
          var win, field, button;
          runs(function() {
              field = document.getElementById('hello');
              button = document.getElementById('fadein');
              expect(util.opacity(field)).toEqual(0);
              simulate(button, 'click');
          });
          runs(function () {
              expect(util.opacity(field)).toEqual(1);
          });
      });

});

                                               UI tests with Jasmine-UI
describeUi("index", "/js-fadein/index.html", function () {

      it("should fade in hello div on button click", function () {
          var win, field, button;
          runs(function() {
              field = document.getElementById('hello');
              button = document.getElementById('fadein');
              expect(util.opacity(field)).toEqual(0);
              simulate(button, 'click');
          });
          runs(function () {
              expect(util.opacity(field)).toEqual(1);
          });
      });

});

                                               UI tests with Jasmine-UI
describeUi("index", "/js-fadein/index.html", function () {

      it("should fade in hello div on button click", function () {
          var win, field, button;
          runs(function() {
              field = document.getElementById('hello');
              button = document.getElementById('fadein');
              expect(util.opacity(field)).toEqual(0);
              simulate(button, 'click');
          });
          runs(function () {
              expect(util.opacity(field)).toEqual(1);
          });
      });

});

                                               UI tests with Jasmine-UI
Instrument

describeUi("index", "/js-fadein/index.html", function () {

      beforeLoad(function() {
          mockBackend();
      });

      ...

});
Instrument

describeUi("index", "/js-fadein/index.html", function () {

      beforeLoad(function() {
          mockBackend();
      });

      ...

});
Instrument

describeUi("index", "/js-fadein/index.html", function () {

      beforeLoad(function() {
          mockBackend();
      });

      ...

});
Jasmine UI: Roadmap


 Support other test runners
     (e.g. testacular)

Support other test frameworks
         (e.g. QUnit)
Present: describeUi



describeUi('todo', '/todo-mobile', function() {
    // ...
});
Future: loadUi
jasmineui.loadUi('/todo-mobile', function() {

      // Jasmine specs
      describe('todo', function() {
          it('should do smth', function() { ... });
      });

      // QUnit tests
      module("todo");
      test("should do smth", function() {
          // ...
      });

});
Automated test execution
Pro               Examples

                Browser from       QUnit
 Testing in
                 production        YUI Test
the browser
                environment        Jasmine

                                   Envjs
              Easier to automate
 Headless                          PhantomJS
                Easier to embed
 browser                           Zombie.js
                      into CI
                                   HtmlUnit
Remote browser control
JsTestDriver




http://code.google.com/p/js-test-driver/
Demo: JsTestDriver
Conclusion

There are a lot of tools for testing JavaScript
                     code.

               Test your code!
    Especially test your JavaScript code!
           You have no excuse ...
Links


Jasmine        http://pivotal.github.com/jasmine/
Jasmine UI     https://github.com/tigbro/jasmine-ui
js-fadein      https://github.com/stefanscheidt/js-fadein
JsTestDriver   http://code.google.com/p/js-test-driver/
saturated writing
    (By Eduordo, http://www.flickr.com/photos/tnarik/366393127/)

                           Smiley Keyboard
   (By ~Prescott, http://www.flickr.com/photos/ppym1/93571524/)

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

                       Sorta synchronised diving
   (By Aaron Retz, http://www.flickr.com/photos/aretz/309469339/)
Stamp Collector
(By C. Castillo, http://www.flickr.com/photos/carolinedecastillo/2750577684/)

                                bios [bible]
      (By Gastev, http://www.flickr.com/photos/gastev/2174505811/)

                          Day 276/365: in hot pursuit
    (By Tina Vega, http://www.flickr.com/photos/tinavega/3066602429/)
Thanks for listening!
       @tigbro
www.opitz-consulting.com/go_mobile

Contenu connexe

Plus de OPITZ CONSULTING Deutschland

Plus de OPITZ CONSULTING Deutschland (20)

OC|Webcast "Daten wirklich nutzen"
OC|Webcast "Daten wirklich nutzen"OC|Webcast "Daten wirklich nutzen"
OC|Webcast "Daten wirklich nutzen"
 
Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"
Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"
Architecture Room Stuttgart - "Cloud-native ist nur ein Teil des Spiels!"
 
OC|Webcast "Willkommen in der Cloud!"
OC|Webcast "Willkommen in der Cloud!"OC|Webcast "Willkommen in der Cloud!"
OC|Webcast "Willkommen in der Cloud!"
 
OC|Webcast "Die neue Welt der Virtualisierung"
OC|Webcast "Die neue Welt der Virtualisierung"OC|Webcast "Die neue Welt der Virtualisierung"
OC|Webcast "Die neue Welt der Virtualisierung"
 
10 Thesen zur professionellen Softwareentwicklung
10 Thesen zur professionellen Softwareentwicklung10 Thesen zur professionellen Softwareentwicklung
10 Thesen zur professionellen Softwareentwicklung
 
OC|Webcast: Oracle Lizenzierung - Lizenznews 2021
OC|Webcast: Oracle Lizenzierung - Lizenznews 2021OC|Webcast: Oracle Lizenzierung - Lizenznews 2021
OC|Webcast: Oracle Lizenzierung - Lizenznews 2021
 
OC|Webcast: Oracle Lizenzierung - Die größten Fallen in der Praxis
OC|Webcast: Oracle Lizenzierung - Die größten Fallen in der PraxisOC|Webcast: Oracle Lizenzierung - Die größten Fallen in der Praxis
OC|Webcast: Oracle Lizenzierung - Die größten Fallen in der Praxis
 
OC|Webcast: Oracle Lizenzierung - Virtualisierung und Cloud
OC|Webcast: Oracle Lizenzierung - Virtualisierung und CloudOC|Webcast: Oracle Lizenzierung - Virtualisierung und Cloud
OC|Webcast: Oracle Lizenzierung - Virtualisierung und Cloud
 
OC|Webcast: Grundlagen der Oracle-Lizenzierung
OC|Webcast: Grundlagen der Oracle-LizenzierungOC|Webcast: Grundlagen der Oracle-Lizenzierung
OC|Webcast: Grundlagen der Oracle-Lizenzierung
 
OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!
OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!
OC|Weekly Talk: Inspect’n’Adapt – Make Change come true!
 
OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...
OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...
OC|Webcast: Schnell und clever in die AWS Cloud – Migrationsszenarien und Han...
 
OC|Weekly Talk The Power of DevOps…
OC|Weekly Talk  The Power of DevOps…OC|Weekly Talk  The Power of DevOps…
OC|Weekly Talk The Power of DevOps…
 
OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...
OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...
OC|Weekly Talk: "Das müsste man mal digitalisieren" - Mit Low-Code schnell zu...
 
OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?
OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?
OC|Weekly Talk: Service Management – Was hat sich durch Corona geändert?
 
OC|Weekly Talk - Digitales Coaching & Smart Sparring
OC|Weekly Talk - Digitales Coaching & Smart Sparring OC|Weekly Talk - Digitales Coaching & Smart Sparring
OC|Weekly Talk - Digitales Coaching & Smart Sparring
 
OC|Weekly Talk - Beratung remote
OC|Weekly Talk - Beratung remoteOC|Weekly Talk - Beratung remote
OC|Weekly Talk - Beratung remote
 
Effiziente Betriebsoptimierung durch Cloud Nutzung
Effiziente Betriebsoptimierung durch Cloud NutzungEffiziente Betriebsoptimierung durch Cloud Nutzung
Effiziente Betriebsoptimierung durch Cloud Nutzung
 
OC|Weekly Talk - Mitarbeiterführung in Zeiten von Social Distance
OC|Weekly Talk - Mitarbeiterführung in Zeiten von Social DistanceOC|Weekly Talk - Mitarbeiterführung in Zeiten von Social Distance
OC|Weekly Talk - Mitarbeiterführung in Zeiten von Social Distance
 
OC|Weekly Talk Remote Design Thinking
OC|Weekly Talk Remote Design ThinkingOC|Weekly Talk Remote Design Thinking
OC|Weekly Talk Remote Design Thinking
 
OC|Webcast Smart Innovation am 7. April 2020
OC|Webcast Smart Innovation am 7. April 2020OC|Webcast Smart Innovation am 7. April 2020
OC|Webcast Smart Innovation am 7. April 2020
 

Dernier

Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Dernier (20)

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
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
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
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
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
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 

Test Driven JavaScript Development – WebTechConference 2012

  • 1. Test Driven JavaScript Development Tobias Bosch OPITZ CONSULTING Deutschland GmbH
  • 3. Mission Markets The company's ambition is to help  Branchspreading organizations to be better than their  Over 600 customers competitors. 29% Trade / Logistics / Our services take place in partnership and 29% Supplier Industry / Services / are aimed at a co-operation of many years. Telecommunications 42% Public Clients / Banks and Insurance Associations and Federations Portfolio Basic Data  Business IT Alignment  Founded in 1990  Business Information Management  400 employees  Business Process Management  8 offices  Application Development  SOA and System Integration  IT Infrastructure Management <Präsentationstitel – bitte im Folienmaster ändern> © OPITZ CONSULTING GmbH 2011 Seite 3
  • 4.
  • 6. This talk is about... ... automatic tests ... written by developers
  • 7. Why should I test?
  • 8. Why should I test JavaScript code?
  • 9. Runtime environments for JavaScript ...
  • 10. In this talk Icon Set by Paul Irish (http://paulirish.com/2010/high-res-browser-icons/)
  • 13. „Classic style“ with xUnit asserts „BDD style“ à la RSpec
  • 14. Demo: BDD with Jasmine
  • 15. Hello Jasmine! expect(x).toEqual(y); expect(x).toBe(y); expect(x).toBeDefined(); expect(x).toBeUndefined(); expect(x).toBeTruthy(); expect(x).toBeFalsy(); ...
  • 17. Spies
  • 18. Spies describe("execute fadein", function() { it("should eventually set opacity to 1", function () { var element = document.createElement("div"); jasmine.Clock.useMock(); spyOn(util, 'opacity'); fadein.execute(element); jasmine.Clock.tick(1000); var mostRecentCall = util.opacity.mostRecentCall; expect(mostRecentCall.args[0]).toBe(element); expect(mostRecentCall.args[1]).toEqual(1); }); });
  • 19. Spies describe("execute fadein", function() { it("should eventually set opacity to 1", function () { var element = document.createElement("div"); jasmine.Clock.useMock(); spyOn(util, 'opacity'); fadein.execute(element); jasmine.Clock.tick(1000); var mostRecentCall = util.opacity.mostRecentCall; expect(mostRecentCall.args[0]).toBe(element); expect(mostRecentCall.args[1]).toEqual(1); }); });
  • 20. Spies describe("execute fadein", function() { it("should eventually set opacity to 1", function () { var element = document.createElement("div"); jasmine.Clock.useMock(); spyOn(util, 'opacity'); fadein.execute(element); jasmine.Clock.tick(1000); var mostRecentCall = util.opacity.mostRecentCall; expect(mostRecentCall.args[0]).toBe(element); expect(mostRecentCall.args[1]).toEqual(1); }); });
  • 21. Spies describe("execute fadein", function() { it("should eventually set opacity to 1", function () { var element = document.createElement("div"); jasmine.Clock.useMock(); spyOn(util, 'opacity'); fadein.execute(element); jasmine.Clock.tick(1000); var mostRecentCall = util.opacity.mostRecentCall; expect(mostRecentCall.args[0]).toBe(element); expect(mostRecentCall.args[1]).toEqual(1); }); });
  • 22. Spies describe("execute fadein", function() { it("should eventually set opacity to 1", function () { var element = document.createElement("div"); jasmine.Clock.useMock(); spyOn(util, 'opacity'); fadein.execute(element); jasmine.Clock.tick(1000);of 'element' to 'opacity' // set opacity var mostRecentCall = util.opacity.mostRecentCall; util.opacity = function (element, opacity) { ... expect(mostRecentCall.args[0]).toBe(element); }; expect(mostRecentCall.args[1]).toEqual(1); }); });
  • 23. Spies describe("execute fadein", function() { it("should eventually set opacity to 1", function () { var element = document.createElement("div"); jasmine.Clock.useMock(); spyOn(util, 'opacity'); fadein.execute(element); jasmine.Clock.tick(1000); var mostRecentCall = util.opacity.mostRecentCall; expect(mostRecentCall.args[0]).toBe(element); expect(mostRecentCall.args[1]).toEqual(1); }); });
  • 24. Spies describe("execute fadein", function() { it("should eventually set opacity to 1", function () { var element = document.createElement("div"); jasmine.Clock.useMock(); spyOn(util, 'opacity'); fadein.execute(element); jasmine.Clock.tick(1000); var mostRecentCall = util.opacity.mostRecentCall; expect(mostRecentCall.args[0]).toBe(element); expect(mostRecentCall.args[1]).toEqual(1); }); });
  • 25. Spies describe("execute fadein", function() { it("should eventually set opacity to 1", function () { var element = document.createElement("div"); jasmine.Clock.useMock(); spyOn(util, 'opacity'); fadein.execute(element); jasmine.Clock.tick(1000); var mostRecentCall = util.opacity.mostRecentCall; expect(mostRecentCall.args[0]).toBe(element); expect(mostRecentCall.args[1]).toEqual(1); }); });
  • 26. Spies describe("execute fadein", function() { it("should eventually set opacity to 1", function () { // set opacity of 'element' to 'opacity' util.opacity = function (element, opacity) { var element = document.createElement("div"); ... jasmine.Clock.useMock(); }; spyOn(util, 'opacity'); fadein.execute(element); jasmine.Clock.tick(1000); var mostRecentCall = util.opacity.mostRecentCall; expect(mostRecentCall.args[0]).toBe(element); expect(mostRecentCall.args[1]).toEqual(1); }); });
  • 27. Function The spy should... spy.andCallThrough() ... call the original function spy.andReturn(argument) ... return the given argument spy.andThrow(exception) ... throw the given exception spy.andCallFake(function) ... call the given function Functions of spies
  • 28. Function Checks whether the spy... toHaveBeenCalled() ... has been called ... has been called with the given toHaveBeenCalledWith(args) arguments Matcher for spies Function Description spy.callCount Number of calls spy.argsForCall[i] Arguments of the i-th call spy.mostRecentCall.args Arguments of the last call Properties of spies
  • 30. Asynchronous 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); }); });
  • 31. Asynchronous 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); }); });
  • 32. Asynchronous 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); }); });
  • 33. Asynchronous 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 // set opacity of 'element' to 'opacity' expect(opacitySpy.mostRecentCall.args[1]).toEqual(1); { util.opacity = function (element, opacity) }); ... }); };
  • 34. Asynchronous 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); }); });
  • 35. UI tests with Jasmine UI
  • 36. Jasmine UI Extension of JS test framework Jasmine Allows to load, instrument and test a webapp in the browser Supports testing asynchronous behaviour
  • 37. Analyse HTML Session Storage Show specs results Scripts: Load Scripts: app jasmine-ui.js jasmine-ui.js jasmine-html.js jasmine-html.js "uiSpec.js" Collect "uiSpec.js" results UiSpecRunner.html UiSpecRunner.html Scripts: "app.js" Execute "uiSpec.js" specs index.html
  • 38. <html> <body> <div id="hello">Hello World!</div> <button id="fadein">Fade in</button> </body> </html> UI tests with Jasmine-UI
  • 39. describeUi("index", "/js-fadein/index.html", function () { it("should fade in hello div on button click", function () { var win, field, button; runs(function() { field = document.getElementById('hello'); button = document.getElementById('fadein'); expect(util.opacity(field)).toEqual(0); simulate(button, 'click'); }); runs(function () { expect(util.opacity(field)).toEqual(1); }); }); }); UI tests with Jasmine-UI
  • 40. describeUi("index", "/js-fadein/index.html", function () { it("should fade in hello div on button click", function () { var win, field, button; runs(function() { field = document.getElementById('hello'); button = document.getElementById('fadein'); expect(util.opacity(field)).toEqual(0); simulate(button, 'click'); }); runs(function () { expect(util.opacity(field)).toEqual(1); }); }); }); UI tests with Jasmine-UI
  • 41. describeUi("index", "/js-fadein/index.html", function () { it("should fade in hello div on button click", function () { var win, field, button; runs(function() { field = document.getElementById('hello'); button = document.getElementById('fadein'); expect(util.opacity(field)).toEqual(0); simulate(button, 'click'); }); runs(function () { expect(util.opacity(field)).toEqual(1); }); }); }); UI tests with Jasmine-UI
  • 42. describeUi("index", "/js-fadein/index.html", function () { it("should fade in hello div on button click", function () { var win, field, button; runs(function() { field = document.getElementById('hello'); button = document.getElementById('fadein'); expect(util.opacity(field)).toEqual(0); simulate(button, 'click'); }); runs(function () { expect(util.opacity(field)).toEqual(1); }); }); }); UI tests with Jasmine-UI
  • 43. describeUi("index", "/js-fadein/index.html", function () { it("should fade in hello div on button click", function () { var win, field, button; runs(function() { field = document.getElementById('hello'); button = document.getElementById('fadein'); expect(util.opacity(field)).toEqual(0); simulate(button, 'click'); }); runs(function () { expect(util.opacity(field)).toEqual(1); }); }); }); UI tests with Jasmine-UI
  • 44. describeUi("index", "/js-fadein/index.html", function () { it("should fade in hello div on button click", function () { var win, field, button; runs(function() { field = document.getElementById('hello'); button = document.getElementById('fadein'); expect(util.opacity(field)).toEqual(0); simulate(button, 'click'); }); runs(function () { expect(util.opacity(field)).toEqual(1); }); }); }); UI tests with Jasmine-UI
  • 45. Instrument describeUi("index", "/js-fadein/index.html", function () { beforeLoad(function() { mockBackend(); }); ... });
  • 46. Instrument describeUi("index", "/js-fadein/index.html", function () { beforeLoad(function() { mockBackend(); }); ... });
  • 47. Instrument describeUi("index", "/js-fadein/index.html", function () { beforeLoad(function() { mockBackend(); }); ... });
  • 48. Jasmine UI: Roadmap Support other test runners (e.g. testacular) Support other test frameworks (e.g. QUnit)
  • 50. Future: loadUi jasmineui.loadUi('/todo-mobile', function() { // Jasmine specs describe('todo', function() { it('should do smth', function() { ... }); }); // QUnit tests module("todo"); test("should do smth", function() { // ... }); });
  • 52. Pro Examples Browser from QUnit Testing in production YUI Test the browser environment Jasmine Envjs Easier to automate Headless PhantomJS Easier to embed browser Zombie.js into CI HtmlUnit
  • 56. Conclusion There are a lot of tools for testing JavaScript code. Test your code! Especially test your JavaScript code! You have no excuse ...
  • 57. Links Jasmine http://pivotal.github.com/jasmine/ Jasmine UI https://github.com/tigbro/jasmine-ui js-fadein https://github.com/stefanscheidt/js-fadein JsTestDriver http://code.google.com/p/js-test-driver/
  • 58. saturated writing (By Eduordo, http://www.flickr.com/photos/tnarik/366393127/) Smiley Keyboard (By ~Prescott, http://www.flickr.com/photos/ppym1/93571524/) Spyhole, Paris (By smith of smiths, http://www.flickr.com/photos/hesketh/232015302/) Sorta synchronised diving (By Aaron Retz, http://www.flickr.com/photos/aretz/309469339/)
  • 59. Stamp Collector (By C. Castillo, http://www.flickr.com/photos/carolinedecastillo/2750577684/) bios [bible] (By Gastev, http://www.flickr.com/photos/gastev/2174505811/) Day 276/365: in hot pursuit (By Tina Vega, http://www.flickr.com/photos/tinavega/3066602429/)