Pro Yearly is on sale from $80 to $50! »

一から始めるJavaScriptユニットテスト/js-unit-test-from-scratch

0ac642c69b7f699a69e3ae3372244dc6?s=47 shibayu36
December 03, 2016

 一から始めるJavaScriptユニットテスト/js-unit-test-from-scratch

buiderscon tokyo 2016で発表した資料です

0ac642c69b7f699a69e3ae3372244dc6?s=128

shibayu36

December 03, 2016
Tweet

Transcript

  1. Ұ͔Β࢝ΊΔ JavaScriptϢχοτςετ 2016/12/03 builderscon shiba_yu36

  2. ࣗݾ঺հ • @shiba_yu36 • ΋͘͠͸shibayu36 • גࣜձࣾ͸ͯͳ • খઆ౤ߘαΠτʮΧΫϤϜʯ

  3. ͷJS؀ڥ

  4. ΧΫϤϜͷJS؀ڥ • MVPΞʔΩςΫνϟ • ίϯϙʔωϯτ͝ͱʹϑΝΠϧΛࡉ͔͘෼ׂ • ϑϨʔϜϫʔΫ͸ͳ͠ɻDOMૢ࡞͸jQuery • ReactͳͲʹ௅ઓ͸͠ͳ͔ͬͨ

  5. ࠷ॳʹ৺ʹܾΊͨ͜ͱ • શJSϑΝΠϧʹϢχοτςετΛॻ͘։ൃΛ͍ͨ͠ • ࣮ࡍͷΞϓϦέʔγϣϯαʔόͳ͠Ͱͷςετ • ϑϩϯτΤϯυͰ΋ఘΊͨ͘ͳ͍

  6. ࠷ॳʹ৺ʹܾΊͨ͜ͱ • શJSϑΝΠϧʹϢχοτςετΛॻ͘։ൃΛ͍ͨ͠ • ࣮ࡍͷΞϓϦέʔγϣϯαʔόͳ͠Ͱͷςετ • ϑϩϯτΤϯυͰ΋ఘΊͨ͘ͳ͍ ୭Ͱ΋؆୯ʹςετͰ͖Δ ؀ڥ࡞ΓΛ࢝Ίͨ

  7. ݱࡏͲ͏ͳ͔ͬͨ • શͯͷϑΝΠϧʹϢχοτςετ͕ଘࡏ • ௨ৗͷؔ਺͔ΒɺDOMૢ࡞ͷ͋Δػೳ·Ͱ • timerɾajaxɾlocalStorageͳͲʹؔΘΔػೳʹ΋

  8. ϢχοτςετͰಘΒΕͨޮೳ ҆৺ײ ։ൃ଎౓ ݁߹࣌Ҏ֎ ϒϥ΢βݟͳ͍ͷͰ

  9. ͔͠͠… • ؀ڥ༻ҙͷͨΊɺ࠷ॳʹௐ΂Δ͜ͱɾ΍Δ͜ͱ ͕ଟ͔ͬͨ • πʔϧ͸ἧ͍ͬͯΔ͕ɺͲ͏࢖͑͹Α͍͔Θ͔ Γʹ͍͘

  10. ͔͠͠… • ؀ڥ༻ҙͷͨΊɺ࠷ॳʹௐ΂Δ͜ͱɾ΍Δ͜ͱ ͕ଟ͔ͬͨ • πʔϧ͸ἧ͍ͬͯΔ͕ɺͲ͏࢖͑͹Α͍͔Θ͔ Γʹ͍͘ ಋೖͷෑډ͕ߴ͍ʂʂʂʂ

  11. ࠓ೔࿩͍ͨ͜͠ͱ • Ϣχοτςετ؀ڥΛ࡞ͬͨํ๏Λɺγϯϓϧͳ ྫΛ࢖ͬͯ঺հ • JSςετͷಋೖͷෑډΛԼ͛ΒΕͨΒ

  12. ࠓ೔࿩͞ͳ͍͜ͱ • E2Eςετ • ಛఆϑϨʔϜϫʔΫʹґଘͨ͠ςετํ๏ • ReactɺAngular • ࠓճͷํ๏Ͱ΋Ͱ͖Δ͔΋ʁ

  13. ΞδΣϯμ •JSͷςετπʔϧΛ੔ཧ͢Δ •௨ৗͷؔ਺ͷϢχοτςετ •DOMૢ࡞͢ΔػೳͷϢχοτςετ •ͦͷଞ༷ʑͳػೳͷςετ

  14. ΞδΣϯμ •JSͷςετπʔϧΛ੔ཧ͢Δ •௨ৗͷؔ਺ͷϢχοτςετ •DOMૢ࡞͢ΔػೳͷϢχοτςετ •ͦͷଞ༷ʑͳػೳͷςετ

  15. ΞδΣϯμ •JSͷςετπʔϧΛ੔ཧ͢Δ •௨ৗͷؔ਺ͷϢχοτςετ •DOMૢ࡞͢ΔػೳͷϢχοτςετ

  16. JSͷςετπʔϧΛ ੔ཧ͢Δ

  17. JSͷϢχοτςετ ؀ڥΛ࡞Δͧʂʂ

  18. ʮJavaScript ςετʯ

  19. assert chai Mocha Karma power-assert Jasmine Sinon.js

  20. assert chai Mocha Karma power-assert Jasmine Sinon.js ʁʁʁʁ

  21. ໾ׂ͝ͱʹ੔ཧ͠Α͏

  22. Ξαʔγϣϯ ʮ˓˓ʯ͸ʮxxʯͰ͋Δ assert, chai, power-assert ϑϨʔϜϫʔΫ ςετ࣮ߦ& ศརΩοτҰࣜ Mocha, Jasmine

    ςετϥϯφʔ ϒϥ΢βΛհͨ͠ςετ Karma ςετπʔϧ ༻్ʹԠͯ͡ Sinon.js, etc
  23. Ξαʔγϣϯ ʮ˓˓ʯ͸ʮxxʯͰ͋Δ assert, chai, power-assert ϑϨʔϜϫʔΫ ςετ࣮ߦ& ศརΩοτҰࣜ Mocha, Jasmine

    ςετϥϯφʔ ϒϥ΢βΛհͨ͠ςετ Karma ςετπʔϧ ༻్ʹԠͯ͡ Sinon.js, etc ಉҰ໾ׂͷ΋ͷ͸࠷େ̍ͭͣͭ
  24. Ξαʔγϣϯ ʮ˓˓ʯ͸ʮxxʯͰ͋Δ assert, chai, power-assert ϑϨʔϜϫʔΫ ςετ࣮ߦ& ศརΩοτҰࣜ Mocha, Jasmine

    ςετϥϯφʔ ϒϥ΢βΛհͨ͠ςετ Karma ςετπʔϧ ༻్ʹԠͯ͡ Sinon.js, etc πʔϧ͸ඞཁͳ΋ͷΛਵ࣌
  25. Ξαʔγϣϯ ʮ˓˓ʯ͸ʮxxʯͰ͋Δ assert, chai, power-assert ϑϨʔϜϫʔΫ ςετ࣮ߦ& ศརΩοτҰࣜ Mocha, Jasmine

    ςετϥϯφʔ ϒϥ΢βΛհͨ͠ςετ Karma ςετπʔϧ ༻్ʹԠͯ͡ Sinon.js, etc
  26. Ξαʔγϣϯ ʮ˓˓ʯ͸ʮxxʯͰ͋Δ assert, chai, power-assert ϑϨʔϜϫʔΫ ςετ࣮ߦ& ศརΩοτҰࣜ Mocha, Jasmine

    ςετϥϯφʔ ϒϥ΢βΛհͨ͠ςετ Karma ςετπʔϧ ༻్ʹԠͯ͡ Sinon.js, etc
  27. Ξαʔγϣϯ ʮ˓˓ʯ͸ʮxxʯͰ͋Δ assert, chai, power-assert ϑϨʔϜϫʔΫ ςετ࣮ߦ& ศརΩοτҰࣜ Mocha, Jasmine

    ςετϥϯφʔ ϒϥ΢βΛհͨ͠ςετ Karma ςετπʔϧ ༻్ʹԠͯ͡ Sinon.js, etc
  28. Ξαʔγϣϯ ʮ˓˓ʯ͸ʮxxʯͰ͋Δ assert, chai, power-assert ϑϨʔϜϫʔΫ ςετ࣮ߦ& ศརΩοτҰࣜ Mocha, Jasmine

    ςετϥϯφʔ ϒϥ΢βΛհͨ͠ςετ Karma ςετπʔϧ ༻్ʹԠͯ͡ Sinon.js, etc ຊൃදͰ͸͜ͷࡾͭΛબ୒
  29. ΞδΣϯμ •JSͷςετπʔϧΛ੔ཧ͢Δ •௨ৗͷؔ਺ͷϢχοτςετ •DOMૢ࡞͢ΔػೳͷϢχοτςετ

  30. ͔͜͜Β͸ίʔυΛ࢖͍·͢ • Github: shibayu36/bcon-js-unit-test • src/js/ʹ࣮૷ɺsrc/js/test/ʹςετ • ޙͰࢀরͯ͠Έ͍ͯͩ͘͞

  31. ௨ৗͷؔ਺ͷϢχοτςετ branch: assert-mocha PR#1

  32. ςετ͍࣮ͨ͠૷ function addNumber(num1, num2) { return num1 + num2; }

    export { addNumber } src/js/number-util.js
  33. addNumberͷϢχοτςετΛ ࡞ΕΔΑ͏ʹ͠·͠ΐ͏

  34. Ξαʔγϣϯ ʮ˓˓ʯ͸ʮxxʯͰ͋Δ assert, chai, power-assert ϑϨʔϜϫʔΫ ςετ࣮ߦ& ศརΩοτҰࣜ Mocha, Jasmine

    ςετϥϯφʔ ϒϥ΢βΛհͨ͠ςετ Karma ςετπʔϧ ༻్ʹԠͯ͡ Sinon.js, etc ؔ਺ͷςετ -> ΞαʔγϣϯͱϑϨʔϜϫʔΫ
  35. assert • ΞαʔγϣϯϥΠϒϥϦͷதͰҰ൪γϯϓϧ • assert.equal(num, 3, ‘਺ࣈ͕ਖ਼͍͠’) • deepEqual, throws

    • https://www.npmjs.com/package/assert
  36. Mocha • ςετ࣮ߦίϚϯυmocha • ग़ྗܗࣜ੾Γସ͑(ਓ༻, CI༻, etc) • describe, itʹΑΔςετͷάϧʔϐϯά

    • ͦͷଞςετศརΩοτҰࣜ
  37. Πϯετʔϧ $ npm install assert $ npm install mocha

  38. babelͷढറ $ npm install babel-preset-es2015 $ npm install babel-register {

    "presets": ["es2015"] } .babelrc
  39. import assert from 'assert'; import { addNumber } from "../number-util";

    describe('addNumber', function () { it('଍͠ࢉͰ͖Δ', function () { assert.equal(addNumber(1, 2), 3, '1 + 2 = 3'); }); }); ςετΛॻ͘ src/js/test/number-util.js
  40. ςετΛ࣮ߦ͢Δ $(npm bin)/mocha --require babel-register src/js/test/*.js

  41. σϞ

  42. ςετ੒ޭ

  43. ςετࣦഊ

  44. assert ςετJS ࣮૷JS mochaίϚϯυ ݁Ռग़ྗ ݱࡏͷςετ؀ڥ mocha src/js/test/*.js

  45. ௨ৗͷؔ਺ͷϢχοτ ςετ؀ڥΛ࡞੒Ͱ͖ͨ

  46. ͍ΘΏΔModel૚ͷςετ͸ ͜͜·Ͱͷ؀ڥͰςετͰ͖Δ

  47. ΞδΣϯμ •JSͷςετπʔϧΛ੔ཧ͢Δ •௨ৗͷؔ਺ͷϢχοτςετ •DOMૢ࡞͢ΔػೳͷϢχοτςετ

  48. DOMૢ࡞͢Δػೳͷ Ϣχοτςετ

  49. DOMૢ࡞͢Δػೳ • Web։ൃΛ΍͍ͬͯΔͱDOMૢ࡞͸ආ͚ΒΕͳ͍ • શϑΝΠϧςετͷͨΊɺ͜ͷΑ͏ͳ࣌΋ςετ͸ ͍ͨ͠

  50. ୯७ͳྫ: Ϧετʹ௥Ճ͢Δػೳ <ul class=“list”> </ul> ul = document.querySelector(‘.list’); appendList(ul, ‘ཁૉ1’);

    <ul class=“list”> <li>ཁૉ1</li> </ul>
  51. appendList(ul, ‘ཁૉ2’); <ul class=“list”> <li>ཁૉ1</li> <li>ཁૉ2</li> </ul> <ul class=“list”> <li>ཁૉ1</li>

    </ul> ୯७ͳྫ: Ϧετʹ௥Ճ͢Δػೳ
  52. src/js/append-list.js function appendList(ul, text) { let li = document.createElement('li'); li.textContent

    = text; ul.appendChild(li); } export { appendList }
  53. 2ͭͷ՝୊ • Ͳ͏΍ͬͯDOMૢ࡞Ͱ͖Δϒϥ΢βͰςετ Λಈ͔͔͢ • Ͳ͏΍ͬͯػೳΛ୯ମͰςετ͢Δ͔ • ࣮ࡍͷHTMLΛ഑৴͢ΔαʔόʔΛ࢖Θͣʹ

  54. 2ͭͷ՝୊ • Ͳ͏΍ͬͯDOMૢ࡞Ͱ͖Δϒϥ΢βͰςετ Λಈ͔͔͢ • Ͳ͏΍ͬͯػೳΛ୯ମͰςετ͢Δ͔ • ࣮ࡍͷHTMLΛ഑৴͢ΔαʔόʔΛ࢖Θͣʹ

  55. Ͳ͏΍ͬͯDOMૢ࡞Ͱ͖Δ ϒϥ΢βͰςετΛಈ͔͔͢ ςετϥϯφʔͷKarmaͰղܾ

  56. Karma • CUIίϚϯυ͚ͩͰɺDOM APIͷ͋Δϒϥ΢β Λհͯ͠ςετ࣮ߦ • ϒϥ΢βͰςετΛ͢ΔͨΊʹɺલॲཧͳͲͷ ػೳ΋ఏڙͯ͘͠ΕΔ

  57. ग़ྗ ग़ྗ ग़ྗ લॲཧ ςετJS ίϚϯυ ࣮ߦ

  58. KarmaΛ࢖ͬͯaddNumberͷ ςετΛϒϥ΢βͰಈ͔͠·͠ΐ͏ branch: karma PR#2

  59. ࠓճ͸ChromeͰ ग़ྗ ग़ྗ ग़ྗ લॲཧ ςετJS ίϚϯυ ࣮ߦ

  60. Πϯετʔϧ $ npm install karma $ npm install karma-browserify browserify

    babelify watchify $ npm install karma-chrome-launcher $ npm install karma-mocha
  61. Πϯετʔϧ $ npm install karma $ npm install karma-browserify browserify

    babelify watchify $ npm install karma-chrome-launcher $ npm install karma-mocha લॲཧ༻ ϒϥ΢βͭͳ͗ࠐΈ ςετϑϨʔϜϫʔΫͭͳ͗ࠐΈ
  62. ॳظઃఆ • $(npm bin)/karma init • ࣭໰ʹ౴͍͑ͯ͘ͱɺkarma.conf.js͕Ͱ͖Δ • karma.conf.jsΛฤू •

    ϑϨʔϜϫʔΫɺલॲཧɺϒϥ΢βઃఆ
  63. // ϑϨʔϜϫʔΫઃఆ frameworks: ['mocha', 'browserify'], // ςετϑΝΠϧ৔ॴ files: [ 'src/js/test/*.js'

    ], karma.conf.js
  64. // લॲཧઃఆ preprocessors: { 'src/js/test/*.js': ['browserify'] }, browserify: { transform:

    ['babelify'], }, // ར༻͢Δϒϥ΢βઃఆ browsers: ['Chrome'],
  65. ࣮ߦ͢Δ $(npm bin)/karma start

  66. ςετΛϒϥ΢βܦ༝Ͱ ಈ͔ͤͨ

  67. 2ͭͷ՝୊ • Ͳ͏΍ͬͯDOM APIͷ͋Δϒϥ΢βͰςετΛ ಈ͔͔͢ • Ͳ͏΍ͬͯػೳΛ୯ମͰςετ͢Δ͔ • ࣮ࡍͷαʔόʔΛ࢖Θͣʹ

  68. Ͳ͏΍ͬͯػೳΛ ୯ମͰςετ͢Δ͔ branch: dom-api-unit-test PR#3

  69. ΞΠσΞ • ػೳʹඞཁͳ࠷খݶͷHTMLஅยΛಡΈࠐΉ • JSΛ࣮ߦ͠ͳ͕ΒɺHTMLߏ଄ͷมԽ͕ҙਤ ௨Γ͔͔֬ΊΔ

  70. ςετલʹ࠷খݶͷHTMLΛ༻ҙ <html><body> <ul class=“list”></ul> </body></html>

  71. JSΛ࣮ߦͯ͠ςετ <html><body> <ul class=“list”></ul> </body></html> ul = document.querySelector(‘.list’); appendList(ul, ‘ཁૉ1’);

    <html><body> <ul class=“list”> <li>ཁૉ1</li> </ul> </body></html>
  72. import assert from 'assert'; import { appendList } from '../append-list';

    document.body.innerHTML = '<ul class="list"></ul>'; let ul = document.querySelector('.list'); assert.equal(ul.children.length, 0, '࠷ॳ͸0݅'); appendList(ul, 'ཁૉ1'); assert.equal(ul.children.length, 1, '݅਺͕1݅ʹ'); assert.equal(ul.children[0].textContent, 'ཁૉ1'); src/js/test/append-list.js
  73. import assert from 'assert'; import { appendList } from '../append-list';

    document.body.innerHTML = '<ul class="list"></ul>'; let ul = document.querySelector('.list'); assert.equal(ul.children.length, 0, '࠷ॳ͸0݅'); appendList(ul, 'ཁૉ1'); assert.equal(ul.children.length, 1, '݅਺͕1݅ʹ'); assert.equal(ul.children[0].textContent, 'ཁૉ1'); src/js/test/append-list.js ςετલʹHTMLΛೖΕΔ
  74. import assert from 'assert'; import { appendList } from '../append-list';

    document.body.innerHTML = '<ul class="list"></ul>'; let ul = document.querySelector('.list'); assert.equal(ul.children.length, 0, '࠷ॳ͸0݅'); appendList(ul, 'ཁૉ1'); assert.equal(ul.children.length, 1, '݅਺͕1݅ʹ'); assert.equal(ul.children[0].textContent, 'ཁૉ1'); src/js/test/append-list.js JSΛ࣮ߦ͠ཁૉΛ͔֬ΊΔ
  75. import assert from 'assert'; import { appendList } from '../append-list';

    document.body.innerHTML = '<ul class="list"></ul>'; let ul = document.querySelector('.list'); assert.equal(ul.children.length, 0, '࠷ॳ͸0݅'); appendList(ul, 'ཁૉ1'); assert.equal(ul.children.length, 1, '݅਺͕1݅ʹ'); assert.equal(ul.children[0].textContent, 'ཁૉ1'); src/js/test/append-list.js
  76. ࣮ߦ͢Δ $(npm bin)/karma start

  77. DOMૢ࡞͢Δػೳ΋ ςετͰ͖ͨ

  78. HTMLஅย͕ڊେͩͱςετ͕Ԛ͘… Ұ͚ͭͩ໰୊

  79. document.body.innerHTML = '<button id="modal-panel-open-buton">ϞʔμϧදࣔϘ λϯ</button><div class="modal- container"><div class="model-panel">Ϟʔμ ϧͷ಺༰<button>Ϟʔμϧด͡ΔϘλϯ</ button></div></div>';

  80. document.body.innerHTML = '<button id="modal-panel-open-buton">ϞʔμϧදࣔϘ λϯ</button><div class="modal- container"><div class="model-panel">Ϟʔμ ϧͷ಺༰<button>Ϟʔμϧด͡ΔϘλϯ</ button></div></div>';

  81. HTMLஅย͕ڊେͩͱςετ͕Ԛ͘… karma-html2js-preprocessor Ұ͚ͭͩ໰୊

  82. karma-html2js-preprocessor • karmaͷલॲཧϓϥάΠϯ • HTMLஅยΛϑΝΠϧͰஔ͍͓ͯ͘ͱɺ ؆୯ʹಡΈࠐΈͰ͖Δπʔϧ

  83. Πϯετʔϧ $ npm install karma-html2js-preprocessor

  84. // html΋௥Ճ files: [ 'src/js/test/*.js', 'src/js/test/*.html' ], // લॲཧઃఆʹϓϥάΠϯ௥Ճ preprocessors:

    { 'src/js/test/*.js': ['browserify'], 'src/js/test/*.html': ['html2js'] }, karma.conf.js
  85. <ul class="list"> </ul> src/js/test/append-list.html

  86. document.body.innerHTML = __html__['src/js/test/append-list.html']; __html__[‘ϑΝΠϧ໊’]ͰಡΈࠐΊΔΑ͏ʹ

  87. HTMLஅย͕େ͖ͯ͘΋ ςετ͕Ԛ͘ͳΔ͜ͱ͕ͳ͘ͳͬͨ

  88. σϞ

  89. ௨ৗͷؔ਺΋ɺDOMૢ࡞ͷ͋Δػೳ΋ ςετΛ࡞ΕΔ؀ڥ͕׬੒ʂ ࣮ߦ͸karma start͚ͩ

  90. CIͰಈ͔͍ͨ͠ • ϒϥ΢βʹphantomjs΍jsdomΛ࢖͏ • jsdom͸node͚ͩͰಈ͘ϔουϨεϒϥ΢β • --reportersͷࢦఆͰCI༻ͷग़ྗ͕Ͱ͖Δ

  91. ςετJS ࣮૷JS ςετHTML html2js ࠷ऴߏ੒ karma start

  92. ࠷ऴߏ੒ ग़ྗ ग़ྗ ग़ྗ html2js

  93. ·ͱΊ • Ϣχοτςετ؀ڥΛҰ͔Βಋೖ͢Δํ๏ • ௨ৗͷؔ਺ͷςετͳΒassert + MochaͰ

  94. ·ͱΊ • DOMૢ࡞͢ΔػೳͷςετͳΒɺKarma + HTMLஅยಡΈࠐΈͰ • timerɺajaxɺlocalStorageͳͲͷςετ͸ผͷػ ձʹ • 12/5ͷ͸ͯͳΤϯδχΞΞυϕϯτΧϨϯμʔͰॻ͖·͢

  95. JSͷϢχοτςετ؀ڥ͸ Ұ௨ΓἧͬͨͷͰ͋ͱ͸΍͍͖ͬͯ·͠ΐ͏ʂ