
今更だけど、データ圧縮についてまとめてみたい
TECH
最終更新日:2022.12.23
更新日:2024.03.12
編集部注:2024年3月12日にリンク切れを修正しました。
お世話になっております、藤本です。
昨今、ユニットテストという言葉がどこからでも聞こえてくるようになってまいりました。弊社も最近では、各所で「テスト」という言葉が飛び交っており、ただ作るだけからしっかりと品質を担保した開発へシフトしているように感じます。
しかし、テストは大事なことですが開発スピードを落としてビジネスチャンスを逃すようでは元も子もありません。開発スピードも品質も担保していきたい。そんな要望に答えて現れたのが、CI(継続的インテグレーション)です。自動化されたビルドとテストを行ってくれるシステムです。
私たちはコードを書き、変更をPushするだけでテストが回るわけです。ここで問題があれば、それを修正し再度Pushします。テストコードは書きますが(これが一番アレだったりしますが…)、これまでのユニットテストがなかった頃と負荷は変わりません。
ここでは、javascriptでCIを取り入れ、自動テストが回っている状態までを作ってみたいと思います。CIと聞くと難しそうなのですが、割とあっさりと導入できることを体感していただければと思います。
Web開発な方で、自動テストに興味がある方。
※ GITの知識やGitHubの知識やアカウントはある前提で書いています。
今回は、「Jest」でのテスト環境の準備から「Travis CI」での自動テスト実行までを取り扱います。
今回の環境にあるものを簡単に説明します。
Travis CI – Test and Deploy Your Code with Confidence
GitHubと連携して、自動でテストやビルドなどを回してくれるサービスです。
privateリポジトリは有料ですが、publicリポジトなら無料で利用できます。 GitHubのプロジェクトで
こんなマークを見たことはありませんか? これはTravis CIのビルド結果のバッチです。 このようなバッチを自分のプロジェクトに追加することで、正常にテスト、ビルドが行われていることをユーザーに示すことができます。
Facebookの開発している、javascript向けのテストライブラリ(テストランナー + テストフレームワーク)です。 テストライブラリは色々とありますが、今回はシンプルなものを選択しています。 設定ファイルなどはなく。「*.test.js」という名前でテスト用のファイルを書き、「Jest」コマンドを実行するだけでテストしてくれます。 ReactやTypescriptなど対応しておりシンプルながら対応範囲も広いです。
知る人ぞ知る、サーバーサイドJavascriptです。 サーバーサイドと書いている通り、サーバー上やお使いのPC上で実行できるjavascriptです。ブラウザはいりません。 これが出たことで、バックエンドな処理もJSで書いたり、コマンドをJSで実装したりできるようになりました。 今回は「Jest」を実行するために使います。 フロントエンドなツールはNode.jsでできているものが多いので入れておいて損はありません。
【余談】
Node.jsのバージョン管理はNVS (Node Version Switcher)がおすすめです。 Windows、Mac、Linux対応なのでどのOSでも同じように使えます。
電卓のWebアプリを作成します。
電卓のコアになる「Calculator.js」を作成しこれに対してテストを実行します。 今回のサンプルで作成したプロジェクトを公開しておりますので参考にしてください。
CIの流れとしては以下のようになります。
[作業PC] ソース変更・テスト作成 → [GitHub] → [TravisCI] 自動テスト
publicなリポジトリを作成してください。名前などはご自分でわかるもので、好きに付けてください。このリポジトリに今回のソースコードを入れて動作確認を行っていきます。
https://travis-ci.org/にアクセスしてください。サインアップボタンがありますので、押すとGitHubとの連携になります。GitHubにログインし連携を進めてください。
以下のようなTravisCIのダッシュボードにたどり着けば登録完了です。
それでは、それぞれ作成していきましょう。 完成した表示はこのようになる想定です。
(明らかにButtonが少ないのは気にしないでください。)
ここにNode.jsでのプロジェクトの設定を書きます。今回は、Jestをインストールする項目と、テストにJestを使う設定が大事な部分です。 ※ 細かい部分は説明を省きます。
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "name": "sample-web-jest-ci", "version": "1.0.0", "description": "", "dependencies": {}, "devDependencies": { "jest": "^22.2.2" }, "scripts": { "test": "jest" }, } |
devDependenciesの項目にJestのバージョンを指定しています。
scriptsのtest部分にテスト実行コマンドを指定します。
package.jsonができたら以下のコマンドでjestをインストールしてください。
1 |
npm install |
node_modulesというフォルダができて、そこにインストールされJestが使える状態になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>でんたく</title> </head> <body> <h1>でんたく</h1> 式:<input type="text" id="formula" value=""><br> 答:<input type="number" id="result" value="0"><br> <button id="n1">1</button><br> <button id="calcSum">+</button><br> <button id="calcEqual">=</button><br> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="my_modules/Calculator.js"></script> <script src="main.js"></script> </body> </html> |
各ボタンのアクションを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
var inputFormula = $('#formula') var inputResult = $('#result') var n1 = $('#n1') var calcSum = $('#calcSum') var calcEqual = $('#calcEqual') n1.on('click', clickN1) calcSum.on('click', clickCalcSum) calcEqual.on('click', clickCalcEqual) var calculator = new Calculator(); function clickN1 () { clickInputButton('1') } function clickCalcSum () { clickInputButton('+') } function clickCalcEqual () { execCalc(inputFormula.val()) } function clickInputButton (text) { inputFormula.val(inputFormula.val() + text) } function execCalc (calcText) { // パース var parse = calculator.parseCalcText(calcText) // 実行 var result = 0 switch (parse[2]) { case '+': result = calculator.sum(parse[1], parse[3]) break } // 結果を表示 inputResult.val(result) } |
電卓機能を実装します。 今回は、計算式文字列を分解する機能と足し算機能を実装しています。
また、node.jsのモジュールとしても読み込めるようにするため、ちょっと見慣れない書き方になっているかと思います。
これにより、ブラウザ上でもNode.jsでも動くクラスが実装できます。「Jest」はNode.js上で動くためこのように書いています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
;(function (global) { 'use strict;' function Calculator () { } Calculator.prototype.constructor = Calculator Calculator.prototype.parseCalcText = function (calcText) { var reg = /(\d+)([\+\-\*\/])(\d+)/g var parse = reg.exec(calcText) console.log(parse) return parse } Calculator.prototype.sum = function (a, b) { return Number(a) + Number(b) } // Exports if ('process' in global) { module['exports'] = Calculator } global['Calculator'] = Calculator })((this || 0).self || global) |
ここまでできたら一度ブラウザで表示と動作を確認してみてください。「1+1」などの簡単な計算ができるはずです。
ソースの場所はどこでもいいのですが今回は↓のようにしています。
tests/Calculator.test.js
※ Jestは、「__tests__
」フォルダの中、もしくは「*.spec.js
」or「*.test.js
」という拡張子のファイルをテストファイルとして認識してくれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// テスト対象クラスの読み込み var Calculator = require('../my_modules/Calculator') var calc = new Calculator() describe('Calculator', () => { // Calculatorクラスの describe('sum()', () => { // sum()メソッドで it('sum(1, 2) = 3', () => { // 1, 2を渡したら3が返ってくるかテスト expect(calc.sum(1, 2)).toBe(3) }) it('sum("99", "100") = 199', () => { // "99", "100"を渡したら199が返ってくるかテスト expect(calc.sum('99', '100')).toBe(199) }) }) }) |
ここでは、先程作ったCalculatorクラスのsum()メソッドのテストを書いてみました。数値を2つ渡すと、それを足した結果が返ってくるメソッドですので、意図した結果かどうかを確認しています。 また、文字列で渡した場合も問題ないかを確認しています。今回はシンプルなメソッドですが、「あれを渡したらコレが返ってくる」の実装が複雑な場合などテストがあるのと無いのとでは安心感が違います。
特に、JSでは型が緩いため今回のように数値を想定していても文字列が渡ってくることもあります。そんな時でも、「意図した動作」をしているかここで担保することができるわけです。 テストを考えるということも、プログラミングの修行の一環として捉えても面白いです。
以下のコマンドを実行します。
※ package.jsonのscriptにてJestが実行されるように設定してあります。
1 |
npm run test |
結果(Windowsの場合です。Macもほぼ同じような出力のはずです。)↓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
PS E:\Projects\sample-web-jest-ci> npm run test > sample-web-jest-ci@1.0.0 test E:\Projects\sample-web-jest-ci > jest PASS tests\Calculator.test.js Calculator sum() √ sum(1, 2) = 3 (2ms) √ sum("99", "100") = 199 Test Suites: 1 passed, 1 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 3.303s Ran all test suites. |
「Tests: 2 passed, 2 total」
と出ているように、2つのテスト中2つ合格しましたよ。と出ています。ここで問題があると、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
PS E:\Projects\sample-web-jest-ci> npm run test > sample-web-jest-ci@1.0.0 test E:\Projects\sample-web-jest-ci > jest FAIL tests\Calculator.test.js Calculator sum() × sum(1, 2) = 3 (5ms) √ sum("99", "100") = 199 ● Calculator › sum() › sum(1, 2) = 3 expect(received).toBe(expected) // Object.is equality Expected value to be: 1 Received: 3 6 | describe('sum()', () => { // sum()メソッドで 7 | it('sum(1, 2) = 3', () => { // 1, 2を渡したら3が返ってくるかテスト > 8 | expect(calc.sum(1, 2)).toBe(1) // !! 意図的にエラー出してます 9 | }) 10 | it('sum("99", "100") = 199', () => { // "99", "100"を渡したら199が返ってくるかテスト 11 | expect(calc.sum('99', '100')).toBe(199) at Object.it (tests/Calculator.test.js:8:30) Test Suites: 1 failed, 1 total Tests: 1 failed, 1 passed, 2 total Snapshots: 0 total Time: 1.136s |
このように失敗した箇所を教えてくれますので、ソースを修正しましょう。
次に、GitHubへプッシュした際にTravisCIが自動でテストを回してくれるように設定していきます。
まずは「.travis.yml」というファイルにTravisCIの動作設定を書いていきます。 今回は実行環境の指定のみですが、ビルドの設定や、デプロイの設定などもここに書いていきます。
1 2 3 |
language: node_js node_js: - "8" |
language:でプログラミング言語の指定、今回はnode_jsです。 node_js:でNode.jsのバージョンを指定します。
次に、TravisCI上で連携の設定をしていきます。 設定は簡単で、対象のリポジトリを「ON」にするだけです。
https://travis-ci.org/profile/にアクセスするとリポジトリ一覧が出ますので、連携したいリポジトリを「ON」にしてください。
以上です。。。簡単ですね。
それでは、 ソースコードに何か修正を入れてGitHubにプッシュしてみてください。 TravisCIの画面を眺めていると、コミットが自動で認識され、テストが回り始めます。
以下のようになるとテスト成功です!!
いかがでしたでしょうか?ちょっと敷居が高そうなイメージのCIがおもったより簡単に導入できました。(個人的には)
今回は、自動テストが行われるだけでしたが、ビルドやデプロイ、結果の通知などを行うことも可能です。masterブランチへマージすることでテストしビルドしデプロイされたらかっこいいのではないでしょうか?
かっこいいだけでなく、デプロイにかかる手間も時間も削減されますね。一度導入してしまえば、勝手に回ってくれますので、CIを意識せず開発に集中できます。
まだユニットテストなんて入れてないよという方も、これを機に導入してみてはいかがでしょう?ユニットテストがあることで、コードの変更時に影響などを気にする範囲が狭くなりますし、書き方自体も意識するようになるので、見通しの良いコードになりますよ。