SlideShare ist ein Scribd-Unternehmen logo
1 von 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

Weitere ähnliche Inhalte

Mehr von OPITZ CONSULTING Deutschland

Mehr von 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
 

Kürzlich hochgeladen

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Kürzlich hochgeladen (20)

The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
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
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
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...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
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
 

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/)