SlideShare une entreprise Scribd logo
1  sur  67
Télécharger pour lire hors ligne
Unit Testing for Great Justice
by Domenic Denicola




                             @domenic
Domenic Denicola
@domenic
https://npmjs.org/profile/domenicdenicola
https://github.com/domenic
https://github.com/NobleJS
q: how do you know your code works?
a: it doesn’t.




                                       @domenic
to make sure something works,
     you need to test it.



                           @domenic
but not manually




                   @domenic
two levels of automated testing


integration testing
unit testing



                                  @domenic
@domenic
today we’re talking about unit testing:


what
why
how
when

                                     @domenic
what is a unit test?




                       @domenic
q: what is a unit?
a: a single function or method




                                  @domenic
A unit test is an automated piece of code
that invokes a function and then checks
assumptions about its logical behavior.




                                          @domenic
// Arrange
var excerpt = "A unit test is an automated piece of code.";
var highlights = [{ start: 2, length: 4, color: "yellow" }];


// Act
var result = highlight(excerpt, highlights);


// Assert
expect(result).to.equal('A <span class="highlight yellow">' +
                           'unit</span> test is an automated ' +
                           'piece of code.');                      @domenic
q: how big should a unit be?
a: about ten lines




                                @domenic
unit tested functions will:
do one thing
do it correctly




                              @domenic
q: what code should you unit test?
a: all the code (that has logic)




                                      @domenic
@domenic
why unit test all the things?




                                @domenic
the most compelling reasoning i’ve
seen comes from this guy




http://butunclebob.com/ArticleS.UncleBob.TheSensitivityProblem   @domenic
“Software is a very sensitive domain. If a single bit of a
100MB executable is wrong, the entire application can
be brought to it's knees. Very few other domains suffer
such extreme sensitivity to error. But one very important
domain does: accounting. A single digit error in a
massive pile of spreadsheets and financial statements
can cost millions and bankrupt an organization.”




                                                             @domenic
“Accountants solved this problem long ago. They use a
set of practices and disciplines that reduce the
probability that errors can go undetected. One of these
practices is Dual Entry Bookkeeping. Every transaction is
entered twice; once in the credit books, and once in the
debit books. The two entries participate in very different
calculations but eventually result in a final result of zero.
That zero means that the all the entries balance. The
strong implication is that there are no single digit errors.”
                                                            @domenic
“We in software have a similar mechanism that provides
a first line of defense: Test Driven Development (TDD).
Every intention is entered in two places: once in a unit
test, and once in the production code. These two entries
follow very different pathways, but eventually sum to a
green bar. That green bar means that the two intents
balance, i.e. the production code agrees with the tests.”




                                                           @domenic
ok, but why unit test all the things?




                                        @domenic
function highlight(excerpt, highlights) {
    if (highlights.length === 0) {
        return excerpt;
    }


    if (highlightsOverlap(highlights)) {
        highlights = subdivideHighlights(highlights);
    }


    var tags = makeTags(highlights);
    var highlighted = insertTags(excerpt, tags);


    return highlighted;
                                                        @domenic

}
more generally:




        A     C                E
Input                                      Output

        B     D                F




                  http://stackoverflow.com/a/11917341/3191
                                                      @domenic
you also get


confidence
the ability to refactor without fear
credibility
free documentation



                                        @domenic
https://gist.github.com/305ad492c2fd20c466be                   @domenic

https://github.com/senchalabs/connect/blob/gh-pages/tests.md
and most importantly, you get
       testable code.




                                @domenic
how do i write testable code?




                                @domenic
the most important thing to remember:
 your tests should only test your code.




                                          @domenic
corollary: in the end, it’s all about
    managing dependencies




                                        @domenic
this is why we use mv* patterns

 the model is all your code: no dependencies
 the view has no logic: no need to test it
 the controller (or whatever) has simple logic and is easy to test using fakes




                                                                           @domenic
this is why we use layered architecture

 the domain model only depends on itself
 the domain services only depend on the models
 the application services only depend on the domain
 the infrastructure code is straightforward translation: easy to test
 the ui code just ties together application services and views




                                                                         @domenic
testing the domain model is easy

// Arrange
var shelf = new Shelf();
var book = { id: "123" };
shelf.addBook(book);


// Act
var hasBook = shelf.hasBook("123");


// Assert
expect(hasBook).to.be.true;

                                      @domenic
spies: a gentle introduction

// Arrange
var shelf = new Shelf();
var book = { id: "123" };


var spy = sinon.spy();
shelf.on("bookAdded", spy);


// Act
shelf.addBook(book);


// Assert
                                             @domenic
expect(spy).to.have.been.calledWith(book);
bdd: an even gentler introduction

https://gist.github.com/3399842




                                    @domenic
testing services is harder

downloader.download(book)
 when the app is offline
    it should callback with a “no internet” error
 when the app is online
    and the DRM service says the user has run out of licenses
        it should callback with a “no licenses left” error
    and the DRM service says the user can download on this
     computer
        and the download succeeds
            it should callback with no error, and the book text
        and the download fails
            it should callback with the underlying error

                                                                   @domenic
when the app is offline, it should
callback with a “no internet” error
// Arrange
var downloader = new Downloader();
var book = { id: "123" };
// ??? how to set up "app is offline"?


// Act
downloader.download(book, function (err) {
      // Assert
      expect(err).to.exist.and.have.property("message", "No internet!");
      done();
});                                                                        @domenic
untestable Downloader

function Downloader() {
    this.download = function (book, cb) {
         if (!navigator.onLine) {
             cb(new Error("No internet!"));
             return;
         }


         // ...
    };
}
                                              @domenic
dependency injection to the rescue!

function Downloader(isOnline) {
    this.download = function (book, cb) {
         if (!isOnline()) {
             cb(new Error("No internet!"));
             return;
         }


         // ...
    };
}
                                              @domenic
app code becomes:

var downloader = new Downloader(function () { return navigator.onLine; });




                                                                        @domenic
test code becomes:

// Arrange
function isOnline() { return false; }
var downloader = new Downloader(isOnline);
var book = { id: "123" };


// …




                                             @domenic
similarly:

function Downloader(isOnline, drmService, doDownloadAjax) {
    this.download = function (book, cb) {
         // https://gist.github.com/3400303
    };
}




                                                              @domenic
testing ui is much like testing services, but
      now you depend on the dom




                                           @domenic
testing ui code
var TodoView = Backbone.View.extend({
      // ... lots of stuff omitted ...


      events: {
           "dblclick label": "edit"
      },


      edit: function () {
           this.$el.addClass("editing");
           this.input.focus();
      }
});                                                                                                   @domenic


                    https://github.com/addyosmani/todomvc/blob/master/architecture-examples/backbone/js/views/todos.js
testing ui code: bad test
setupEntireApplication();
addATodo();
var $todo = $("#todos > li").first();


$todo.find("label").dblclick();


expect($todo.hasClass("editing")).to.be.true;
expect(document.activeElement).to.equal($todo.find(".edit")[0]);




                                                                   @domenic
testing ui code: good test
var todoView = new TodoView();
todoView.$el = $(document.createElement("div"));
todoView.input = { focus: sinon.spy() };


todoView.edit();


expect(todoView.$el.hasClass("editing")).to.be.true;
expect(todoView.input.focus).to.have.been.called;




                                                       @domenic
when should i write my tests?




                                @domenic
let’s talk about code coverage




                                 @domenic
function highlight(excerpt, highlights) {
    if (highlights.length === 0) {
        return excerpt;
    }


    if (highlightsOverlap(highlights)) {
        highlights = subdivideHighlights(highlights);
    }


    var tags = makeTags(highlights);
    var highlighted = insertTags(excerpt, tags);


    return highlighted;
                                                        @domenic

}
 when given a highlight and an excerpt
   it should return the excerpt with highlighting tags inserted




                                                                   @domenic
var excerpt = "A unit test is an automated piece of code.";
var highlights = [{ start: 2, length: 4, color: "yellow" }];




var result = highlight(excerpt, highlights);




expect(result).to.equal('A <span class="highlight yellow">' +
                           'unit</span> test is an automated ' +
                           'piece of code.');                      @domenic
✓ function highlight(excerpt, highlights) {
◌     if (highlights.length === 0) {
✗         return excerpt;
✓     }
✓
◌     if (highlightsOverlap(highlights)) {
✗         highlights = subdivideHighlights(highlights);
✓     }
✓
✓     var tags = makeTags(highlights);
✓     var highlighted = insertTags(excerpt, tags);
✓
✓     return highlighted;
                                                          @domenic

✓ }
q: how can we achieve 100% coverage?
a: use test-driven development




                                   @domenic
the three rules of tdd

 You are not allowed to write any production code unless
  it is to make a failing unit test pass.
 You are not allowed to write any more of a unit test than
  is sufficient to fail.
 You are not allowed to write any more production code
  than is sufficient to pass the one failing unit test.




           http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
                                                                 @domenic
the three steps of tdd

 red
 green
 refactor




                         @domenic
 when there are no highlights
    the excerpt should pass through unchanged




                0/1 tests passed                 @domenic
function highlight(excerpt, highlights) {
    if (highlights.length === 0) {
        return excerpt;
    }
}




                                            @domenic
✓ function highlight(excerpt, highlights) {
◌     if (highlights.length === 0) {
✓         return excerpt;
✓     }
✓ }




                                              @domenic
✓ function highlight(excerpt, highlights) {
✓     return excerpt;
✓ }




                        1/1 tests passed      @domenic
 when there are no highlights
    the excerpt should pass through unchanged
 when there are simple non-overlapping highlights
    it should insert tags around those areas




                  1/2 tests passed                   @domenic
✓ function highlight(excerpt, highlights) {
✓     if (highlights.length === 0) {
✓         return excerpt;
✓     }
✓
✓     var tags = makeTags(highlights);
✓     var highlighted = insertTags(excerpt, tags);
✓
✓     return highlighted;
✓ }




                        2/2 tests passed             @domenic
 when there are no highlights
    the excerpt should pass through unchanged
 when there are simple non-overlapping highlights
    it should insert tags around those substrings
 when there are overlapping highlights
    it should subdivide them before inserting the tags




                  2/3 tests passed                        @domenic
✓ function highlight(excerpt, highlights) {
✓     if (highlights.length === 0) {
✓         return excerpt;
✓     }
✓
✓     if (highlightsOverlap(highlights)) {
✓         highlights = subdivideHighlights(highlights);
✓     }
✓
✓     var tags = makeTags(highlights);
✓     var highlighted = insertTags(excerpt, tags);
✓
✓     return highlighted;
                         3/3 tests passed                 @domenic

✓ }
@domenic
✓ function highlight(excerpt, highlights) {
✓     if (highlightsOverlap(highlights)) {
✓         highlights = subdivideHighlights(highlights);
✓     }
✓
✓     var tags = makeTags(highlights);
✓     var highlighted = insertTags(excerpt, tags);
✓
✓     return highlighted;
✓ }




                       3/3 tests still passing!           @domenic
summary

 Unit tests are automated tests that verify your application’s logic by
  breaking it up into small units.
 Unit testing is like double-entry bookkeeping. It gives you the ability
  to refactor without fear.
 Writing unit tests will lead to writing testable code, which is
  decoupled via dependency injection and thus becomes more
  modular, flexible, and comprehensible.
 The best way to write unit tests is with test-driven development,
  which has three steps: red, green, refactor. Make these steps as
  small as possible.


                                                                     @domenic
unit-testing tools i like

 Mocha test runner: http://mochajs.com
 Chai assertion library: http://chaijs.com
 Sinon.JS spy/stub/mock library: http://sinonjs.org
 Sandboxed-Module environment faker: http://npm.im/sandboxed-module
 Cover code coverage tool: http://npm.im/cover
 My Chai plugins:
     Sinon–Chai: http://npm.im/sinon-chai
     Chai as Promised: http://npm.im/chai-as-promised




                                                                @domenic

Contenu connexe

Tendances

Perl web programming
Perl web programmingPerl web programming
Perl web programmingJohnny Pork
 
Modern Web Development with Perl
Modern Web Development with PerlModern Web Development with Perl
Modern Web Development with PerlDave Cross
 
Lunch and learn: Cucumber and Capybara
Lunch and learn: Cucumber and CapybaraLunch and learn: Cucumber and Capybara
Lunch and learn: Cucumber and CapybaraMarc Seeger
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Fabien Potencier
 
Introduction to Web Programming with Perl
Introduction to Web Programming with PerlIntroduction to Web Programming with Perl
Introduction to Web Programming with PerlDave Cross
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014Matthias Noback
 
The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)Matthias Noback
 
Debugging over tcp and http
Debugging over tcp and httpDebugging over tcp and http
Debugging over tcp and httpKaniska Mandal
 
Flask patterns
Flask patternsFlask patterns
Flask patternsit-people
 
Test automation with Cucumber-JVM
Test automation with Cucumber-JVMTest automation with Cucumber-JVM
Test automation with Cucumber-JVMAlan Parkinson
 
InterConnect: Java, Node.js and Swift - Which, Why and When
InterConnect: Java, Node.js and Swift - Which, Why and WhenInterConnect: Java, Node.js and Swift - Which, Why and When
InterConnect: Java, Node.js and Swift - Which, Why and WhenChris Bailey
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everythingnoelrap
 
Always up to date, testable and maintainable documentation with OpenAPI
Always up to date, testable and maintainable documentation with OpenAPIAlways up to date, testable and maintainable documentation with OpenAPI
Always up to date, testable and maintainable documentation with OpenAPIGOG.com dev team
 
Intoduction to Play Framework
Intoduction to Play FrameworkIntoduction to Play Framework
Intoduction to Play FrameworkKnoldus Inc.
 
Fighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnitFighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnitJames Fuller
 
Jumping Into WordPress Plugin Programming
Jumping Into WordPress Plugin ProgrammingJumping Into WordPress Plugin Programming
Jumping Into WordPress Plugin ProgrammingDougal Campbell
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinMichelangelo van Dam
 
Web develop in flask
Web develop in flaskWeb develop in flask
Web develop in flaskJim Yeh
 

Tendances (20)

Perl web programming
Perl web programmingPerl web programming
Perl web programming
 
Modern Web Development with Perl
Modern Web Development with PerlModern Web Development with Perl
Modern Web Development with Perl
 
Lunch and learn: Cucumber and Capybara
Lunch and learn: Cucumber and CapybaraLunch and learn: Cucumber and Capybara
Lunch and learn: Cucumber and Capybara
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3
 
Introduction to Web Programming with Perl
Introduction to Web Programming with PerlIntroduction to Web Programming with Perl
Introduction to Web Programming with Perl
 
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
High Quality Symfony Bundles tutorial - Dutch PHP Conference 2014
 
Apache Ant
Apache AntApache Ant
Apache Ant
 
The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)The quest for global design principles (SymfonyLive Berlin 2015)
The quest for global design principles (SymfonyLive Berlin 2015)
 
Debugging over tcp and http
Debugging over tcp and httpDebugging over tcp and http
Debugging over tcp and http
 
Flask patterns
Flask patternsFlask patterns
Flask patterns
 
Test automation with Cucumber-JVM
Test automation with Cucumber-JVMTest automation with Cucumber-JVM
Test automation with Cucumber-JVM
 
InterConnect: Java, Node.js and Swift - Which, Why and When
InterConnect: Java, Node.js and Swift - Which, Why and WhenInterConnect: Java, Node.js and Swift - Which, Why and When
InterConnect: Java, Node.js and Swift - Which, Why and When
 
How To Test Everything
How To Test EverythingHow To Test Everything
How To Test Everything
 
Always up to date, testable and maintainable documentation with OpenAPI
Always up to date, testable and maintainable documentation with OpenAPIAlways up to date, testable and maintainable documentation with OpenAPI
Always up to date, testable and maintainable documentation with OpenAPI
 
Intoduction to Play Framework
Intoduction to Play FrameworkIntoduction to Play Framework
Intoduction to Play Framework
 
Fighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnitFighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnit
 
Jumping Into WordPress Plugin Programming
Jumping Into WordPress Plugin ProgrammingJumping Into WordPress Plugin Programming
Jumping Into WordPress Plugin Programming
 
Workshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublinWorkshop quality assurance for php projects - phpdublin
Workshop quality assurance for php projects - phpdublin
 
Web develop in flask
Web develop in flaskWeb develop in flask
Web develop in flask
 
TDD, BDD, RSpec
TDD, BDD, RSpecTDD, BDD, RSpec
TDD, BDD, RSpec
 

Similaire à Unit Testing for Great Justice

Understanding the Node.js Platform
Understanding the Node.js PlatformUnderstanding the Node.js Platform
Understanding the Node.js PlatformDomenic Denicola
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiRan Mizrahi
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive Kuo
 
Serverless in production, an experience report (Going Serverless)
Serverless in production, an experience report (Going Serverless)Serverless in production, an experience report (Going Serverless)
Serverless in production, an experience report (Going Serverless)Yan Cui
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Enginecatherinewall
 
How Testability Inspires AngularJS Design / Ran Mizrahi
How Testability Inspires AngularJS Design / Ran MizrahiHow Testability Inspires AngularJS Design / Ran Mizrahi
How Testability Inspires AngularJS Design / Ran MizrahiRan Mizrahi
 
Serverless in production, an experience report (linuxing in london)
Serverless in production, an experience report (linuxing in london)Serverless in production, an experience report (linuxing in london)
Serverless in production, an experience report (linuxing in london)Yan Cui
 
End-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystemEnd-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystemAlex Mikitenko
 
Electron - cross platform desktop applications made easy
Electron - cross platform desktop applications made easyElectron - cross platform desktop applications made easy
Electron - cross platform desktop applications made easyUlrich Krause
 
Choosing a Javascript Framework
Choosing a Javascript FrameworkChoosing a Javascript Framework
Choosing a Javascript FrameworkAll Things Open
 
Getting Started with Maven and Cucumber in Eclipse
Getting Started with Maven and Cucumber in EclipseGetting Started with Maven and Cucumber in Eclipse
Getting Started with Maven and Cucumber in EclipseTom Arend
 
Serverless in production, an experience report (JeffConf)
Serverless in production, an experience report (JeffConf)Serverless in production, an experience report (JeffConf)
Serverless in production, an experience report (JeffConf)Yan Cui
 
Automatisation in development and testing - within budget
Automatisation in development and testing - within budgetAutomatisation in development and testing - within budget
Automatisation in development and testing - within budgetDavid Lukac
 
RichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile DevicesRichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile DevicesPavol Pitoňák
 
DCEU 18: App-in-a-Box with Docker Application Packages
DCEU 18: App-in-a-Box with Docker Application PackagesDCEU 18: App-in-a-Box with Docker Application Packages
DCEU 18: App-in-a-Box with Docker Application PackagesDocker, Inc.
 

Similaire à Unit Testing for Great Justice (20)

Having Fun with Play
Having Fun with PlayHaving Fun with Play
Having Fun with Play
 
Understanding the Node.js Platform
Understanding the Node.js PlatformUnderstanding the Node.js Platform
Understanding the Node.js Platform
 
Ruby For Startups
Ruby For StartupsRuby For Startups
Ruby For Startups
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
 
Capistrano Overview
Capistrano OverviewCapistrano Overview
Capistrano Overview
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
Serverless in production, an experience report (Going Serverless)
Serverless in production, an experience report (Going Serverless)Serverless in production, an experience report (Going Serverless)
Serverless in production, an experience report (Going Serverless)
 
Capistrano
CapistranoCapistrano
Capistrano
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Engine
 
How Testability Inspires AngularJS Design / Ran Mizrahi
How Testability Inspires AngularJS Design / Ran MizrahiHow Testability Inspires AngularJS Design / Ran Mizrahi
How Testability Inspires AngularJS Design / Ran Mizrahi
 
JavaScript on the Desktop
JavaScript on the DesktopJavaScript on the Desktop
JavaScript on the Desktop
 
Serverless in production, an experience report (linuxing in london)
Serverless in production, an experience report (linuxing in london)Serverless in production, an experience report (linuxing in london)
Serverless in production, an experience report (linuxing in london)
 
End-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystemEnd-to-end web-testing in ruby ecosystem
End-to-end web-testing in ruby ecosystem
 
Electron - cross platform desktop applications made easy
Electron - cross platform desktop applications made easyElectron - cross platform desktop applications made easy
Electron - cross platform desktop applications made easy
 
Choosing a Javascript Framework
Choosing a Javascript FrameworkChoosing a Javascript Framework
Choosing a Javascript Framework
 
Getting Started with Maven and Cucumber in Eclipse
Getting Started with Maven and Cucumber in EclipseGetting Started with Maven and Cucumber in Eclipse
Getting Started with Maven and Cucumber in Eclipse
 
Serverless in production, an experience report (JeffConf)
Serverless in production, an experience report (JeffConf)Serverless in production, an experience report (JeffConf)
Serverless in production, an experience report (JeffConf)
 
Automatisation in development and testing - within budget
Automatisation in development and testing - within budgetAutomatisation in development and testing - within budget
Automatisation in development and testing - within budget
 
RichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile DevicesRichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile Devices
 
DCEU 18: App-in-a-Box with Docker Application Packages
DCEU 18: App-in-a-Box with Docker Application PackagesDCEU 18: App-in-a-Box with Docker Application Packages
DCEU 18: App-in-a-Box with Docker Application Packages
 

Plus de Domenic Denicola

Plus de Domenic Denicola (20)

The State of JavaScript (2015)
The State of JavaScript (2015)The State of JavaScript (2015)
The State of JavaScript (2015)
 
Async Frontiers
Async FrontiersAsync Frontiers
Async Frontiers
 
The jsdom
The jsdomThe jsdom
The jsdom
 
The Final Frontier
The Final FrontierThe Final Frontier
The Final Frontier
 
ES6 in Real Life
ES6 in Real LifeES6 in Real Life
ES6 in Real Life
 
Streams for the Web
Streams for the WebStreams for the Web
Streams for the Web
 
After Return of the Jedi
After Return of the JediAfter Return of the Jedi
After Return of the Jedi
 
The State of JavaScript
The State of JavaScriptThe State of JavaScript
The State of JavaScript
 
How to Win Friends and Influence Standards Bodies
How to Win Friends and Influence Standards BodiesHow to Win Friends and Influence Standards Bodies
How to Win Friends and Influence Standards Bodies
 
The Extensible Web
The Extensible WebThe Extensible Web
The Extensible Web
 
The Promised Land (in Angular)
The Promised Land (in Angular)The Promised Land (in Angular)
The Promised Land (in Angular)
 
ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
 
Boom! Promises/A+ Was Born
Boom! Promises/A+ Was BornBoom! Promises/A+ Was Born
Boom! Promises/A+ Was Born
 
Domains!
Domains!Domains!
Domains!
 
Client-Side Packages
Client-Side PackagesClient-Side Packages
Client-Side Packages
 
Creating Truly RESTful APIs
Creating Truly RESTful APIsCreating Truly RESTful APIs
Creating Truly RESTful APIs
 
Promises, Promises
Promises, PromisesPromises, Promises
Promises, Promises
 
ES6 is Nigh
ES6 is NighES6 is Nigh
ES6 is Nigh
 
Real World Windows 8 Apps in JavaScript
Real World Windows 8 Apps in JavaScriptReal World Windows 8 Apps in JavaScript
Real World Windows 8 Apps in JavaScript
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 

Dernier

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 

Dernier (20)

Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 

Unit Testing for Great Justice

  • 1. Unit Testing for Great Justice by Domenic Denicola @domenic
  • 3. q: how do you know your code works? a: it doesn’t. @domenic
  • 4. to make sure something works, you need to test it. @domenic
  • 5. but not manually @domenic
  • 6. two levels of automated testing integration testing unit testing @domenic
  • 8. today we’re talking about unit testing: what why how when @domenic
  • 9. what is a unit test? @domenic
  • 10. q: what is a unit? a: a single function or method @domenic
  • 11. A unit test is an automated piece of code that invokes a function and then checks assumptions about its logical behavior. @domenic
  • 12. // Arrange var excerpt = "A unit test is an automated piece of code."; var highlights = [{ start: 2, length: 4, color: "yellow" }]; // Act var result = highlight(excerpt, highlights); // Assert expect(result).to.equal('A <span class="highlight yellow">' + 'unit</span> test is an automated ' + 'piece of code.'); @domenic
  • 13. q: how big should a unit be? a: about ten lines @domenic
  • 14. unit tested functions will: do one thing do it correctly @domenic
  • 15. q: what code should you unit test? a: all the code (that has logic) @domenic
  • 17. why unit test all the things? @domenic
  • 18. the most compelling reasoning i’ve seen comes from this guy http://butunclebob.com/ArticleS.UncleBob.TheSensitivityProblem @domenic
  • 19. “Software is a very sensitive domain. If a single bit of a 100MB executable is wrong, the entire application can be brought to it's knees. Very few other domains suffer such extreme sensitivity to error. But one very important domain does: accounting. A single digit error in a massive pile of spreadsheets and financial statements can cost millions and bankrupt an organization.” @domenic
  • 20. “Accountants solved this problem long ago. They use a set of practices and disciplines that reduce the probability that errors can go undetected. One of these practices is Dual Entry Bookkeeping. Every transaction is entered twice; once in the credit books, and once in the debit books. The two entries participate in very different calculations but eventually result in a final result of zero. That zero means that the all the entries balance. The strong implication is that there are no single digit errors.” @domenic
  • 21. “We in software have a similar mechanism that provides a first line of defense: Test Driven Development (TDD). Every intention is entered in two places: once in a unit test, and once in the production code. These two entries follow very different pathways, but eventually sum to a green bar. That green bar means that the two intents balance, i.e. the production code agrees with the tests.” @domenic
  • 22. ok, but why unit test all the things? @domenic
  • 23. function highlight(excerpt, highlights) { if (highlights.length === 0) { return excerpt; } if (highlightsOverlap(highlights)) { highlights = subdivideHighlights(highlights); } var tags = makeTags(highlights); var highlighted = insertTags(excerpt, tags); return highlighted; @domenic }
  • 24. more generally: A C E Input Output B D F http://stackoverflow.com/a/11917341/3191 @domenic
  • 25. you also get confidence the ability to refactor without fear credibility free documentation @domenic
  • 26. https://gist.github.com/305ad492c2fd20c466be @domenic https://github.com/senchalabs/connect/blob/gh-pages/tests.md
  • 27. and most importantly, you get testable code. @domenic
  • 28. how do i write testable code? @domenic
  • 29. the most important thing to remember: your tests should only test your code. @domenic
  • 30. corollary: in the end, it’s all about managing dependencies @domenic
  • 31. this is why we use mv* patterns  the model is all your code: no dependencies  the view has no logic: no need to test it  the controller (or whatever) has simple logic and is easy to test using fakes @domenic
  • 32. this is why we use layered architecture  the domain model only depends on itself  the domain services only depend on the models  the application services only depend on the domain  the infrastructure code is straightforward translation: easy to test  the ui code just ties together application services and views @domenic
  • 33. testing the domain model is easy // Arrange var shelf = new Shelf(); var book = { id: "123" }; shelf.addBook(book); // Act var hasBook = shelf.hasBook("123"); // Assert expect(hasBook).to.be.true; @domenic
  • 34. spies: a gentle introduction // Arrange var shelf = new Shelf(); var book = { id: "123" }; var spy = sinon.spy(); shelf.on("bookAdded", spy); // Act shelf.addBook(book); // Assert @domenic expect(spy).to.have.been.calledWith(book);
  • 35. bdd: an even gentler introduction https://gist.github.com/3399842 @domenic
  • 36. testing services is harder downloader.download(book)  when the app is offline  it should callback with a “no internet” error  when the app is online  and the DRM service says the user has run out of licenses  it should callback with a “no licenses left” error  and the DRM service says the user can download on this computer  and the download succeeds  it should callback with no error, and the book text  and the download fails  it should callback with the underlying error @domenic
  • 37. when the app is offline, it should callback with a “no internet” error // Arrange var downloader = new Downloader(); var book = { id: "123" }; // ??? how to set up "app is offline"? // Act downloader.download(book, function (err) { // Assert expect(err).to.exist.and.have.property("message", "No internet!"); done(); }); @domenic
  • 38. untestable Downloader function Downloader() { this.download = function (book, cb) { if (!navigator.onLine) { cb(new Error("No internet!")); return; } // ... }; } @domenic
  • 39. dependency injection to the rescue! function Downloader(isOnline) { this.download = function (book, cb) { if (!isOnline()) { cb(new Error("No internet!")); return; } // ... }; } @domenic
  • 40. app code becomes: var downloader = new Downloader(function () { return navigator.onLine; }); @domenic
  • 41. test code becomes: // Arrange function isOnline() { return false; } var downloader = new Downloader(isOnline); var book = { id: "123" }; // … @domenic
  • 42. similarly: function Downloader(isOnline, drmService, doDownloadAjax) { this.download = function (book, cb) { // https://gist.github.com/3400303 }; } @domenic
  • 43. testing ui is much like testing services, but now you depend on the dom @domenic
  • 44. testing ui code var TodoView = Backbone.View.extend({ // ... lots of stuff omitted ... events: { "dblclick label": "edit" }, edit: function () { this.$el.addClass("editing"); this.input.focus(); } }); @domenic https://github.com/addyosmani/todomvc/blob/master/architecture-examples/backbone/js/views/todos.js
  • 45. testing ui code: bad test setupEntireApplication(); addATodo(); var $todo = $("#todos > li").first(); $todo.find("label").dblclick(); expect($todo.hasClass("editing")).to.be.true; expect(document.activeElement).to.equal($todo.find(".edit")[0]); @domenic
  • 46. testing ui code: good test var todoView = new TodoView(); todoView.$el = $(document.createElement("div")); todoView.input = { focus: sinon.spy() }; todoView.edit(); expect(todoView.$el.hasClass("editing")).to.be.true; expect(todoView.input.focus).to.have.been.called; @domenic
  • 47. when should i write my tests? @domenic
  • 48. let’s talk about code coverage @domenic
  • 49. function highlight(excerpt, highlights) { if (highlights.length === 0) { return excerpt; } if (highlightsOverlap(highlights)) { highlights = subdivideHighlights(highlights); } var tags = makeTags(highlights); var highlighted = insertTags(excerpt, tags); return highlighted; @domenic }
  • 50.  when given a highlight and an excerpt  it should return the excerpt with highlighting tags inserted @domenic
  • 51. var excerpt = "A unit test is an automated piece of code."; var highlights = [{ start: 2, length: 4, color: "yellow" }]; var result = highlight(excerpt, highlights); expect(result).to.equal('A <span class="highlight yellow">' + 'unit</span> test is an automated ' + 'piece of code.'); @domenic
  • 52. ✓ function highlight(excerpt, highlights) { ◌ if (highlights.length === 0) { ✗ return excerpt; ✓ } ✓ ◌ if (highlightsOverlap(highlights)) { ✗ highlights = subdivideHighlights(highlights); ✓ } ✓ ✓ var tags = makeTags(highlights); ✓ var highlighted = insertTags(excerpt, tags); ✓ ✓ return highlighted; @domenic ✓ }
  • 53. q: how can we achieve 100% coverage? a: use test-driven development @domenic
  • 54. the three rules of tdd  You are not allowed to write any production code unless it is to make a failing unit test pass.  You are not allowed to write any more of a unit test than is sufficient to fail.  You are not allowed to write any more production code than is sufficient to pass the one failing unit test. http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd @domenic
  • 55. the three steps of tdd  red  green  refactor @domenic
  • 56.  when there are no highlights  the excerpt should pass through unchanged 0/1 tests passed @domenic
  • 57. function highlight(excerpt, highlights) { if (highlights.length === 0) { return excerpt; } } @domenic
  • 58. ✓ function highlight(excerpt, highlights) { ◌ if (highlights.length === 0) { ✓ return excerpt; ✓ } ✓ } @domenic
  • 59. ✓ function highlight(excerpt, highlights) { ✓ return excerpt; ✓ } 1/1 tests passed @domenic
  • 60.  when there are no highlights  the excerpt should pass through unchanged  when there are simple non-overlapping highlights  it should insert tags around those areas 1/2 tests passed @domenic
  • 61. ✓ function highlight(excerpt, highlights) { ✓ if (highlights.length === 0) { ✓ return excerpt; ✓ } ✓ ✓ var tags = makeTags(highlights); ✓ var highlighted = insertTags(excerpt, tags); ✓ ✓ return highlighted; ✓ } 2/2 tests passed @domenic
  • 62.  when there are no highlights  the excerpt should pass through unchanged  when there are simple non-overlapping highlights  it should insert tags around those substrings  when there are overlapping highlights  it should subdivide them before inserting the tags 2/3 tests passed @domenic
  • 63. ✓ function highlight(excerpt, highlights) { ✓ if (highlights.length === 0) { ✓ return excerpt; ✓ } ✓ ✓ if (highlightsOverlap(highlights)) { ✓ highlights = subdivideHighlights(highlights); ✓ } ✓ ✓ var tags = makeTags(highlights); ✓ var highlighted = insertTags(excerpt, tags); ✓ ✓ return highlighted; 3/3 tests passed @domenic ✓ }
  • 65. ✓ function highlight(excerpt, highlights) { ✓ if (highlightsOverlap(highlights)) { ✓ highlights = subdivideHighlights(highlights); ✓ } ✓ ✓ var tags = makeTags(highlights); ✓ var highlighted = insertTags(excerpt, tags); ✓ ✓ return highlighted; ✓ } 3/3 tests still passing! @domenic
  • 66. summary  Unit tests are automated tests that verify your application’s logic by breaking it up into small units.  Unit testing is like double-entry bookkeeping. It gives you the ability to refactor without fear.  Writing unit tests will lead to writing testable code, which is decoupled via dependency injection and thus becomes more modular, flexible, and comprehensible.  The best way to write unit tests is with test-driven development, which has three steps: red, green, refactor. Make these steps as small as possible. @domenic
  • 67. unit-testing tools i like  Mocha test runner: http://mochajs.com  Chai assertion library: http://chaijs.com  Sinon.JS spy/stub/mock library: http://sinonjs.org  Sandboxed-Module environment faker: http://npm.im/sandboxed-module  Cover code coverage tool: http://npm.im/cover  My Chai plugins:  Sinon–Chai: http://npm.im/sinon-chai  Chai as Promised: http://npm.im/chai-as-promised @domenic