Upgrade to Pro — share decks privately, control downloads, hide ads and more …

В поисках качества JavaScript кода: модульное тестирование

fwdays
April 28, 2014

В поисках качества JavaScript кода: модульное тестирование

Анна Хабибуллина

fwdays

April 28, 2014
Tweet

More Decks by fwdays

Other Decks in Programming

Transcript

  1. AGENDA  Unit Testing Concept  Pros & Cons 

    Basic Terms & Structure  TDD &/vs. BDD  Tools & Libraries  Unit Testing Specifics in JavaScript  Best Practices
  2. UNIT TESTING CONCEPT Unit testing is a method by which

    individual units of source code are tested to determine if they are fit for use.
  3. WHY UNIT TESTING? Unit tests find problems early in the

    development cycle (TDD & BDD) Refactoring Integration Documentation Better design
  4. IS UNIT TESTING A GOOD INVESTMENT?  slow down the

    development process  share the same blind spots with the code  doesn’t prove that they’re compatible with one another or configured correctly
  5. In simple words, the goal of assertion is to forcefully

    define if the test fails or passes. STATEMENT PASSES FAILS x = 1 assert(x > 0) assert(x < 0) expect(4+5).to.equal(9); ASSERTION
  6. function initialize() { // The initialization was successful. return true;

    } Given the function initialize(): ASSERTION: EXAMPLE
  7. FIXTURE A test fixture is a fixed state of the

    software under test used as a baseline for running tests. In JavaScript for client side: simulate AJAX responses; loading known set of data such as html objects.
  8. FIXTURE: EXAMPLE Require the piece of markup stored in myfixturemarkup.html

    file before each test: beforeEach(function() { loadFixtures('myfixturemarkup.html'); });
  9. STUB: EXAMPLE Forcing a method to throw an error in

    order to test error handling. var fn = foo.stub().throws(Error); expect(fn).to.throw(Error);
  10. SPY A test spy is a function that records arguments,

    return value, the value of this and exception thrown (if any) for all its calls.
  11. SPY: EXAMPLE Test that a function cursor.hide() has been only

    called once, and only once. sinon.spy(cursor, "hide"); TDD sinon.assert.calledOnce(cursor.hide) BDD expect(cursor.hide.calledOnce).to.be.true
  12. MOCK Mocks are fake objects with pre- programmed behavior (like

    stubs) and pre-programmed expectations. They are like both stubs and spies – in one.
  13. MOCK: EXAMPLE Create an expectation that jQuery.each is called once,

    and only once, and also instructs the mock to behave as we pre- define. var mock = sinon.mock(jQuery);
  14. MOCK: EXAMPLE #1 – which method? #2 – how many

    times it is called? #3 – what are the arguments when the method called? #4 – what the method returns?
  15. ALRIGHT, WHAT IS BDD YOU ASK? Terminology: TDD BDD Test

    Example Assertion Expectation Unit Behavior
  16. BASIC STRUCTURE #1. Setup/BeforeEach/Before #2. Prepare an input #3. Call

    a method #4. Check an output #5. Tear down/AfterEach/After
  17. #1. Setup / Before before(function(done) { // Create a basic

    document. document = jsdom.jsdom(); window = document.parentWindow; done(); }); BASIC STRUCTURE: EXPLAINED
  18. Before / BeforeEach before(function() { console.log(‘before test’); }); test(‘first test’,

    function() { console.log(‘first test’); }); test(‘second test’, function() { console.log(‘second test’);}); afterEach(function() { console.log(‘after each test’); }); Result before test first test after each test second test after each test BASIC STRUCTURE: EXPLAINED
  19. BASIC STRUCTURE: EXPLAINED it('should initialize cursor if zoom level >=

    minimum zoom level.', #2. Prepare an input and predicted result. var minZoomLevel = 1; var zoomLevel = minZoomLevel + 0.1; var expectedCursor = {‘color’: ‘white’, ‘height’: … }; #3. Call a method. var actualCursor = cursor.init(zoomLevel); #4. Check an output. expect(actualCursor).to.deep.equal(expectedCursor); done(); }); function(done) {
  20. BASIC STRUCTURE: EXPLAINED it('should initialize cursor if zoom level >=

    minimum zoom level.', #2. Prepare an input and predicted result. var minZoomLevel = 1; var zoomLevel = minZoomLevel + 0.1; var expectedCursor = {‘color’: ‘white’, ‘height’: … }; #3. Call a method. var actualCursor = cursor.init(zoomLevel); #4. Check an output. expect(actualCursor).to.deep.equal(expectedCursor); done(); }); function(done) {
  21. BASIC STRUCTURE: EXPLAINED it('should initialize cursor if zoom level >=

    minimum zoom level.', #2. Prepare an input and predicted result. var minZoomLevel = 1; var zoomLevel = minZoomLevel + 0.1; var expectedCursor = {‘color’: ‘white’, ‘height’: … }; #3. Call a method. var actualCursor = cursor.init(zoomLevel); #4. Check an output. expect(actualCursor).to.deep.equal(expectedCursor); done(); }); function(done) {
  22. BASIC STRUCTURE: EXPLAINED it('should initialize cursor if zoom level >=

    minimum zoom level.', #2. Prepare an input and predicted result. var minZoomLevel = 1; var zoomLevel = minZoomLevel + 0.1; var expectedCursor = {‘color’: ‘white’, ‘height’: … }; #3. Call a method. var actualCursor = cursor.init(zoomLevel); #4. Check an output. expect(actualCursor).to.deep.equal(expectedCursor); done(); }); function(done) {
  23. #5. TearDown / After after(function(done) { // Remove global objects

    document. document = null; window = null; done(); }); BASIC STRUCTURE: EXPLAINED
  24. <testsuite name="Macchiato Tests" tests="13" failures="0" errors="0" skipped="0" timestamp="Mon, 02 Dec

    2013 11:08:09 GMT" time="0.114"> <testcase classname = "cursor #init ()" name = "should initialize cursor if zoom level &gt; minimum zoom level." time="0.004"/> </testsuite> OUTPUT: SUCCESS
  25. <failure classname="cursor #init()" name="should initialize cursor if zoom level &gt;

    minimum zoom level." time="0" message="Cannot read property 'show' of undefined"><![CDATA[TypeError: Cannot read property 'show' of undefined // ..... Exception Stack Trace ..... </failure> OUTPUT: FAILURE
  26. TOOLS > 40 frameworks & libraries qUnit(TDD) light-weight TDD framework

    Jasmine(BDD) flexible BDD framework Mocha / Karma test runner for async code + Chai TDD / BDD assertion library + Sinon test spies, stubs & mocks
  27. HOW DO I UNIT TEST Known Frameworks / Libraries? What

    to test? What to use? Angular, React, Flight Karma + Jasmine Backbone qUnit Ember Karma + qUnit (ember-app-kit) ExtJs Jasmine, Siesta (UI) TypeScript tsUnit CoffeeScript qUnit Dart Unittest, Hop and Drone.io NodeJs expresso and vows, Nodeunit
  28. TOOLS: WHAT WE USE  Run UT: Mocha  Run

    UT in parallel: Macchiato  Assert/Expect: Chai  W3C DOM in JavaScript: Jsdom  Mock, spy, stub: Sinon  Code coverage tool: None  Routine automation: make/Grunt
  29. UNIT TESTING SPECIFICS IN JAVASCRIPT UI Load fake data via

    “fixtures” Jsdom(W3C JavaScript implementation)
  30. UNIT TESTING SPECIFICS IN JAVASCRIPT Dependency Injection Mocking deps in

    RequireJs sucks hard! Squire.js lib / testr.js
  31. BEST PRACTISES Fast Isol ated Consistent Responsibil ity Sel f-descr

    iptive NoexceptionHandl ing Use asser tions whenneeded
  32. WRAPPING UP  Eachtestver ifies a smal lchunk ofcode 

    Unittests wor k bestinisol ation  Mocks, stubs and spies hel p toisol ate test  Don’ttestever ythingbutwr ite many tests  > 40 tool s ar e avail abl e to ease unittesting exper ience, soCHOOSE YOUR OWN!