Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

by Yuya Saito JavaScript Testable ςετ͠΍͍͢JavaScript

Slide 3

Slide 3 text

 @cssradar

Slide 4

Slide 4 text

en.ja OSS https://github.com/enja-oss

Slide 5

Slide 5 text

@CyberAgent

Slide 6

Slide 6 text

Agenda ■ςετ͠΍͍͢JavaScriptͱ͸ ■ϢχοτςετπʔϧͱηοτΞοϓ

Slide 7

Slide 7 text

ςετ͠΍͍͢JavaScriptͱ͸ What is Testable JavaScript?

Slide 8

Slide 8 text

Test. Why? ͳͥςετ͕ඞཁͳͷ͔

Slide 9

Slide 9 text

JavaScript ʮຊ෺ʯ ͷϓϩάϥϛϯάݴޠ΁ਐԽΛ਱͛ͨ

Slide 10

Slide 10 text

Best Practices ‣ ΦϒδΣΫτࢦ޲JavaScript ‣ σβΠϯύλʔϯ ‣ MV*ߏ଄ ‣ Ϣχοτςετ

Slide 11

Slide 11 text

Question on Hacker News ςετͯ͠·͔͢ʁ

Slide 12

Slide 12 text

ςετ͸ॻ͍͍ͯͳ͍ɻ ͕ॻ͖͍ͨͱ͸ࢥ͍ͬͯΔɻ news.ycombinator.com/item?id=3702827

Slide 13

Slide 13 text

શ෦ͷػೳͰ͸ͳ͍͕ɺ ԿΒ͔ͷςετ͸ߦ͍ͬͯΔ news.ycombinator.com/item?id=3702827

Slide 14

Slide 14 text

Father of Test Driven Development(TDD) Kent Beck

Slide 15

Slide 15 text

I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence […]. “ ” - Kent Beck on StackOverflow

Slide 16

Slide 16 text

ςετʹͰ͸ͳ͘ɺ ಈ࡞͢Δίʔυʹ͓ۚΛ ෷ͬͯ໯͍ͬͯΔͷ͔ͩΒɺ ҰఆϨϕϧͷ֬৴͕ಘΒΕΔ࠷খݶͷςετΛ ߦ͏͜ͱ͕ࢲͷϑΟϩιϑΟʔͩ<>ɻ “ ” - Kent Beck on StackOverflow

Slide 17

Slide 17 text

Then, Why?

Slide 18

Slide 18 text

ࠓಈ͍͍ͯΔͷ͔ͩΒͦΕͰ͍͍ ͸ɺ ΋͸΍ݱ࣮తͰ͸ͳ͍

Slide 19

Slide 19 text

ϦϑΝΫλϦϯάΛલఏͰߟ͑Δ “First draft of anything is shit.” - Ernest Hemingway

Slide 20

Slide 20 text

ϩδοΫʹ΋σβΠϯ͕͋Δ Ұ؏ੑͱ࣮֬ੑΛ࣋ͭϩδοΫʹ͸ςετ͕ඞਢ

Slide 21

Slide 21 text

Testing is a tool. Ͳ͏࢖͍͜ͳ͔͢͸ݸਓͷࣗ༝ɻ ্ख͘࢖͍͜ͳͤ͹༷ʑͳλεΫΛָʹͯ͘͠ΕΔ΋ͷɻ

Slide 22

Slide 22 text

Testable JavaScript ςετ͠΍͍͢JavaScriptͱ͸

Slide 23

Slide 23 text

What is Not testable? Not ςετͮ͠Β͍ίʔυͱ͸ͲΜͳ΋ͷͳͷ͔ɻ Ͳ͏ͯ͠ςετͮ͠Β͍ͷ͔ɻ

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

$(document).ready(function() { $('#form-send-mock').on('click', function(e){ e.preventDefault(); var data = { 'quote': $('#quote-text').val(), 'author': $('#author').val(), 'url': $('#source').val() }; $('#quotes').append( '
  • ' + '
    ' + '

    ' + data.quote + '

    ' + '

    ' + '' + '—' + data.author + '' + ' / ' + 'ࢀরݩ' + '

    ' + '
    ' + '
  • ' ); $('#quote-text').val(''); $('#author').val(''); $('#source').val(''); }); });

    Slide 26

    Slide 26 text

    $(document).ready(function() { $('#form-send-mock').on('click', function(e){ var data = { 'quote': $('#quote-text').val(), 'author': $('#author').val(), 'url': $('#source').val() }; $('#quotes').append( '
  • ' + '
    ' + '

    ' + data.quote + '

    ' + '

    ' + '' + '—' + data.author + '' + ' / ' + 'ࢀরݩ' + '

    ' + '
    ' + '
  • ' ); $('#quote-text').val(''); $('#author').val(''); $('#source').val(''); }); });

    Slide 27

    Slide 27 text

    $.ajax({ type: 'POST', url: '/post/', data: data, dataType: 'json', success: function(data) { // Get data from the server } });

    Slide 28

    Slide 28 text

    $.ajax({ type: 'POST', url: '/post/', data: data, dataType: 'json', success: function(data) { // Get data from the server } });

    Slide 29

    Slide 29 text

    ᶃjQueryͷreadyΠϕϯτ ᶄ#form-send-mockͷclickΠϕϯτ ᶅϑΥʔϜͷΠϯϓοτ͔ΒσʔλΛऔಘ ᶆappend()ʹΑΔDOMૢ࡞ ᶇHTMLͷੜ੒ ᶈωοτϫʔΫIO ᶉsuccessͷωοτϫʔΫΠϕϯτ

    Slide 30

    Slide 30 text

    ίʔυͷ໾ׂ෼୲͕ෳࡶͰɺ ίʔυͷ໾ׂ͕ີ઀ͳؔ܎Λ͍࣋ͬͯΔͱ ςετΛߦ͏͜ͱ͕೉͘͠ͳΔɻ

    Slide 31

    Slide 31 text

    ςετΛॻ͘ͷ͕೉͍͠ɺ ͷͰ͸ͳ͘ɺ ςετΛ͍ͯ͠Δίʔυʹ໰୊͕͋Δͱ ߟ͑Δํ͕ࣗવɻ

    Slide 32

    Slide 32 text

    Benefit of TDD ςετۦಈ։ൃͷར఺

    Slide 33

    Slide 33 text

    ςετΛલఏͱͯ͠ίʔυΛॻ͘Ҏ্ɺ ςετͮ͠Β͍ίʔυΛॻ͘͜ͱ͸ෆՄೳɻ ͔͠͠ʜʜ

    Slide 34

    Slide 34 text

    ςετʹ׳Εͳ͍͏ͪʹɺ ςετۦಈ։ൃΞϓϩʔνΛߦ͏ͷ͸ ೉͍͠ɻ

    Slide 35

    Slide 35 text

    One of the Coolest things that will happen to you as a developer is you'd take the test first approach, you write a bunch of tests, you write a code that make the tests pass and you fire up the application and then it works.[…] so at least try testing first sometime to just experience that. “ ” - Rebecca Murphey at Full Frontal 2012

    Slide 36

    Slide 36 text

    ςετϑΝʔετͷΞϓϩʔνΛͯ͠ɺ ͨ͘͞ΜͷςετΛॻ͖ɺ ͦͯͦ͠ͷςετΛ ΫϦΞ͢ΔίʔυΛॻ͘ɻ ͦͯ͠ΞϓϦέʔγϣϯΛ্ཱͪ͛Δͱɺ ͦΕ͕͖ͪΜͱಈ࡞͍ͯ͠Δɻ ͜Ε͸σϕϩούͱͯ͠࠷ߴʹΫʔϧͳ ॠؒͩɻ ͜ͷମݧΛ͢ΔͨΊ͚ͩͰ΋ ςετϑΝʔετʹ௅ઓͯ͠Έͯཉ͍͠ɻ “ ” - Rebecca Murphey at Full Frontal 2012

    Slide 37

    Slide 37 text

    Test-Driven Refactoring ςετۦಈϦϑΝΫλϦϯά

    Slide 38

    Slide 38 text

    ςετۦಈ։ൃ͸σβΠϯϓϩηε

    Slide 39

    Slide 39 text

    ࣮ફςετۦಈ։ൃςετʹಋ͔Εͯ ΦϒδΣΫτࢦ޲ιϑτ΢ΣΞΛҭͯΔ by Steve Freeman, Nat Price www.amazon.co.jp/dp/4798124583

    Slide 40

    Slide 40 text

    Starting with a test means that we have to describe what we what to achieve before we consider how. “ ” - Steve Freeman, Nat Price

    Slide 41

    Slide 41 text

    ςετ͔Β࢝ΊΔͱ͍͏͜ͱ͸ɺ Ͳ͏΍ͬͯΛ ߟ͑Δલʹɺ ԿΛ͍ͨ͠ͷ͔Λઆ໌͠ͳ͚Ε͹ ͳΒͳ͍ͱ͍͏͜ͱͩɻ “ ” - Steve Freeman, Nat Price

    Slide 42

    Slide 42 text

    $(document).ready(function() { $('#form-send-mock').on('click', function(e){ e.preventDefault(); var data = { 'quote': $('#quote-text').val(), 'author': $('#author').val(), 'url': $('#source').val() }; $('#quotes').append( '
  • ' + '
    ' + '

    ' + data.quote + '

    ' + '

    ' + '' + '—' + data.author + '' + ' / ' + 'ࢀরݩ' + '

    ' + '
    ' + '
  • ' ); $('#quote-text').val(''); $('#author').val(''); $('#source').val(''); }); });

    Slide 43

    Slide 43 text

    Refactoring. How? ςετ͠΍͍͢JavaScript΁ͷ ϦϑΝΫλϦϯά

    Slide 44

    Slide 44 text

    Architect Christopher Alexander

    Slide 45

    Slide 45 text

    Each pattern describes a problem that occurs over and over again in our environment, and then describes the core of the solution to that problem, in such way that you can use this solution a million times over, without ever doing it the same way twice. “ ” - Christopher Alexandar

    Slide 46

    Slide 46 text

    ύλʔϯͱ͸ͦΕͧΕզʑ͕ੜ͖͍ͯΔ؀ڥͷ தͰԿ౓΋܁Γฦ͠ൃੜ͢Δ໰୊Λઆ໌͢Δ ΋ͷͰ͋Γɺ ͦΕΒͷ໰୊ʹର͢ΔίΞͱͳΔ ղܾΛઆ໌͢Δ΋ͷͰ΋͋Γ·͢ɻ ίΞͱͳΔղܾͱ͸ͦͷղܾํ๏Λಉ͜͡ͱΛ ܁Γฦͣ͞ɺ ਺ඦສճͰ΋ར༻Ͱ͖Δ΋ͷͰ͢ɻ “ ” - Christopher Alexandar

    Slide 47

    Slide 47 text

    Use Module Pattern Qunit and

    Slide 48

    Slide 48 text

    var qof = { //͜ͷதʹίʔυΛهड़͍͖ͯ͠·͢ɻ };

    Slide 49

    Slide 49 text

    var qof = { init: function() { // EPDVNFOU SFBEZ GVODUJPO \ʜ^ ͷத਎Λίϐʔ } };

    Slide 50

    Slide 50 text

    test('Namespace', function() { equal(window.qof, true, 'Namespace is qof and public'); });

    Slide 51

    Slide 51 text

    xͱΠϯϓοτͨ͠Βɺ y͕Ξ΢τϓοτ͞ΕΔ͔ʁ Unit Test is:

    Slide 52

    Slide 52 text

    test()ؔ਺͸ୈҰҾ਺ʹςετ͢ΔϢχοτΛએݴ͠ɺ ୈೋҾ਺ͰίʔϧόοΫؔ਺Λ࣮ߦɻ equal()ؔ਺͸ΞαʔγϣϯAPIͷͭͰɺ ୈҰҾ਺ʹςετ͞ΕΔΦϒδΣΫτɺ ୈೋҾ਺ʹظ଴͢Δ݁Ռɺ ͦͯ͠ୈࡾҾ਺ʹϝοηʔδΛ౉͢ɻ

    Slide 53

    Slide 53 text

    test('Namespace', function() { equal(window.qof, true, 'Namespace is qof and public'); });

    Slide 54

    Slide 54 text

    test('Initialize', function() { equal(window.qof.init, true, 'Init method is ready to go'); });

    Slide 55

    Slide 55 text

    test('User input values are good to go', function() { qof.init(); equal( qof.getData().quote, 'quote', 'quote is in #quote-text' ); equal( qof.getData().author, 'author', 'author is in #author' ); equal( qof.getData().url, 'url', 'url is in #source' ); });

    Slide 56

    Slide 56 text

    ςετ݁Ռ

    Slide 57

    Slide 57 text

    var qof = { init: function() { $('#form-send-mock').on('click', function(e){ var data = this.getData(); // লུ }); }, getData: function() { return { 'quote': $('#quote-text').val(), 'author': $('#author').val(), 'url': $('#source').val() }; } }; var qof = { init: function() { $('#form-send-mock').on('click', function(e){ var data = this.getData(); // লུ }); }, getData: function() { return { 'quote': $('#quote-text').val(), 'author': $('#author').val(), 'url': $('#source').val() }; } };

    Slide 58

    Slide 58 text

    Write programs that do one thing and do it well. - Doug McIlroy, Father of Unix “ ”

    Slide 59

    Slide 59 text

    ୯Ұ੹೚ͷݪଇ Principles of OOP:

    Slide 60

    Slide 60 text

    test('Generate HTML from input data', function() { expect(1); var html = qof.template(); var dummy = '
  • ' + '
    ' + '

    ' + 'quote'+ '

    ' + '

    ' + '' + '—' + 'author' + '' + ' / ' + 'ࢀরݩ + '' + '

    ' + '
    ' + '
  • '; equal( html, dummy, 'Templating is working' ); });

    Slide 61

    Slide 61 text

    template: function() { var data = qof.getData(); var html = '
  • ' + '
    ' + '

    ' + data.quote + '

    ' + '

    ' + '' + '—' + data.author + '' + ' / ' + ' + 'ࢀরݩ' + '

    ' + '
    ' + '
  • '; return html; }, render: function() { var html = qof.template(); $('#quotes').append(html); }

    Slide 62

    Slide 62 text

    module( 'Templating', { setup: function() { $('#quote-text').val('quote'); $('#author').val('author'); $('#source').val('url'); }, teardown: function() { $('#quote-text').val(''); $('#author').val(''); $('#source').val(''); } } );

    Slide 63

    Slide 63 text

    ϑΥʔϜ͔ΒσʔλΛऔಘ͠ ͦͷσʔλ͔ΒHTMLΛੜ੒͢Δ Business Logic:

    Slide 64

    Slide 64 text

    github.com/studiomohawk/QOF

    Slide 65

    Slide 65 text

    ςετπʔϧͱηοςΟϯά Tools & Settings

    Slide 66

    Slide 66 text

    Tools for Testing Ϣχοτςετπʔϧ

    Slide 67

    Slide 67 text

    Jasmine

    Slide 68

    Slide 68 text

    pivotal.github.com/jasmine

    Slide 69

    Slide 69 text

    Jasmine-standalone

    Slide 70

    Slide 70 text

    ςετ݁Ռ: Jasmine

    Slide 71

    Slide 71 text

    describe("Namespace", function() { it("should be qof", function() { expect(qof).to.exist; }); });

    Slide 72

    Slide 72 text

    Qunit

    Slide 73

    Slide 73 text

    qunitjs.com

    Slide 74

    Slide 74 text

    ςετ݁Ռ: QUnit

    Slide 75

    Slide 75 text

    test("Namespace", function() { ɹok(window.qof, 'Namespace is qof and public'); });

    Slide 76

    Slide 76 text

    module("Module 1") test("some test", function() { //ςετΛهड़ }); module("Module 2") test("some test", function() { //ςετΛهड़ });

    Slide 77

    Slide 77 text

    Mocha

    Slide 78

    Slide 78 text

    visionmedia.github.com/mocha/

    Slide 79

    Slide 79 text

    ςετ݁Ռ: Mocha

    Slide 80

    Slide 80 text

    describe("A suite", function() { it("contains spec with an expectation", function() { expect(true).to.be.true; }); });

    Slide 81

    Slide 81 text

    Phantom.JS

    Slide 82

    Slide 82 text

    phantomjs.org

    Slide 83

    Slide 83 text

    github.com/studiomohawk/js-testing-boilerplates/wiki

    Slide 84

    Slide 84 text

    Setup for Test Ϣχοτςετઃఆ

    Slide 85

    Slide 85 text

    ςετͷࣗಈԽ Automation

    Slide 86

    Slide 86 text

    ໘౗ͳ܁Γฦ͠ʹͳΔ͜ͱ͸ࣗಈԽ͠ɺ େࣄͳ͜ͱʹ࣌ؒΛׂ͚ΔΑ͏ʹ͢Δɻ ʰ ʱ ࠤ౻าat Frontrend Vol.3

    Slide 87

    Slide 87 text

    gruntjs.com

    Slide 88

    Slide 88 text

     Grunt 0.4.x is BETA!

    Slide 89

    Slide 89 text

    github.com/studiomohawk/js-testing-boilerplates

    Slide 90

    Slide 90 text

    Test-flight the Test Ϣχοτςετʹ৮ΕͯΈΔ

    Slide 91

    Slide 91 text

    JavaScript Koans JavaScriptΛֶͿͨΊͷެҊ

    Slide 92

    Slide 92 text

    github.com/studiomohawk/javascript-koans

    Slide 93

    Slide 93 text

    ϢχοτςετΛ࢖ͬͯ JavaScriptʹ͍ͭͯͷษڧ͕Ͱ͖Δ by David Laing (@mrdavidlaing)

    Slide 94

    Slide 94 text

    ·ͣ͸(JU)VC͔ΒϨϙδτϦΛΫϩʔϯ͠·͢ɻ ຋༁ͷ͍ͭͰʹ(SVOUΛ࢖ͬͨࣗಈԽΛ࣮૷ͨ͠ ϒϥϯνΛ࡞੒͠·ͨ͠ɻ git clone --branch=ja-koan-with-grunt git://github.com/studiomohawk/javascript- koans.git ~/Documents/learning-unit-test/javascript- koans

    Slide 95

    Slide 95 text

    Ϋϩʔϯͨ͠σΟϨΫτϦʹҠಈ͠·͢ɻ cd ~/Documents/learning-unit-test/javascript- koans HSVOUΛ࣮ߦ grunt

    Slide 96

    Slide 96 text

    ϒϥ΢βʹͯҎԼΛ։͍͍ͯͩ͘͞ɻ ίϚϯυϥΠϯʹ΋ςετ݁Ռ͸දࣔ͞Ε·͢ɻ ͕ɺύε͠ͳ͍΋ͷ΋ؚΊͯ͢΂ͯදࣔ͞Εͯ͠·͏ͷͰ ݟͮΒ͍Ͱ͢ɻ localhost:8000/KoansRunner.html

    Slide 97

    Slide 97 text

    ࠷ॳͷ໰୊͸koans/AboutExpects.jsϑΝΠϧ ʹ͋Γ·͢ɻ ͓࢖͍ͷΤσΟλͰϑΝΠϧΛ։͍ͯԼ͍͞ɻ mvim koans/AboutExpects.js

    Slide 98

    Slide 98 text

    No content

    Slide 99

    Slide 99 text

    ·ͱΊ Final Words

    Slide 100

    Slide 100 text

    ςετ͠΍͍͢JavaScriptͱ͸ What is Testable JavaScript? Recap

    Slide 101

    Slide 101 text

    ςετ͠΍͍͢JavaScriptΛॻ͘ ʮΑΓΑ͍ίʔυʯΛॻͨ͘Ίͷ αϙʔτπʔϧ͕ςετ Recap

    Slide 102

    Slide 102 text

    ϓϩάϥϜ΋σβΠϯ͢Δ΋ͷ ςετ͸໰୊ղܾ΁ͷΨΠυ Recap

    Slide 103

    Slide 103 text

    ςετπʔϧͱηοςΟϯά Tools & Settings Recap

    Slide 104

    Slide 104 text

    ·ͣ͸ςετΛॻ͍ͯΈΔॴ͔Β Ͳͷπʔϧʹ΋ಘҙͳ෦෼͕͋Γ ෆಘҙͳ෦෼͕͋Δ Recap

    Slide 105

    Slide 105 text

    ࣗಈԽͷઃఆΛ͢Δ͜ͱ ؀ڥΛ੔͑ͯ͠·͑͹ ݴ͍༁͸ͮ͠Β͘ͳΔ Recap

    Slide 106

    Slide 106 text

    Why do we fall, sir? So that we can learn to pick ourselves up. “ ” - Alfred Pennyworth from Batman Begins

    Slide 107

    Slide 107 text

    Thank You!