メモ: JavaScriptのテスト対象コードとテストコードのファイルを分ける

JavaScript本のサンプルコードを写経して、それに対してテストコードを書いてみたところ、コレジャナイ感にあふれていたので、身内に質問して教えてもらったことをメモします。

Before

最初はこういうのを書いていました。

これは、JavaScript The Good Parts 第3章の写経とテストコードです。オブジェクトにプロパティを設定して、値を取り出せることを確認しています。node+mochaで実行します。

var assert = require('assert');

describe('Object', function(){
    it('3.1. should return value by name', function(){
        var empty_object = {};
        
        var stooge = {
            "first-name" : "Jarome",
            "last-name" : "Howard"
        };
        assert(stooge['first-name'] === "Jarome");
        assert(stooge['last-name'] === "Howard");
    })
});

describe('Object', function(){
    it('3.1. should return value by name', function(){
        var flight = {
            airline: "Oceanic",
            number: 815, 
            departure: {
                IATA: "SYD",
                time: "2004-09-22 14:55",
                city: "Sydney"
            },
            arrival: {
               IATA: "LAX",
               time: "2004-09-23 10:42",
               city: "Los Angels"
            }
        };
        assert(flight['airline'] === "Oceanic");
        assert(flight.departure.IATA === "SYD");
        assert(flight.foo === undefined);
    })
});

何に悩んでいたかというと、テストコードの中にテスト対象のオブジェクトが混ざり込んでいるところです。上のようなやり方では、テストケースごとにstoogeやflightを定義しなければいけません。

たとえば、Javaを書くとき、srcフォルダ以下にプロダクトコードを置き、testフォルダ以下にテストコードを置くといったことをします。JavaScriptでもテスト対象コードとテストコードをファイルレベルで分けるハズだと思いますが、JS弱者には"ふつうのやり方"が分かりません\(~o~)/

After

そういう時は、テスト対象コードをモジュールにすればいいよーと教えてもらいました。

テスト対象コード(ch3.js)

exports.Stooge = {
    "first-name" : "Jarome",
    "last-name" : "Howard"
}

exports.Flight = {
    airline: "Oceanic",
    number: 815, 
    departure: {
        IATA: "SYD",
        time: "2004-09-22 14:55",
        city: "Sydney"
    },
    arrival: {
        IATA: "LAX",
        time: "2004-09-23 10:42",
        city: "Los Angels"
    }
}

テストコード(test3_1.js)

var assert = require('assert');
var obj = require("./ch3");

describe('Object', function(){
    it('3.1. should return value by name', function(){
        var stooge = obj.Stooge;
        
        assert(stooge['first-name'] === "Jarome");
        assert(stooge['last-name'] === "Howard");
    })
});

describe('Object', function(){
    it('3.1. should return value by name', function(){
        var flight = obj.Flight;
        
        assert(flight['airline'] === "Oceanic");
        assert(flight.departure.IATA === "SYD");
    })
});

おぉ、写経+テストコードらしくなりました。ありがとうございます。

もちろん、ライブラリを作るような場合は、小さなファイルに分割して開発とテストを行い、最後にコンパイルして1つのファイルにまとめるようなことをするそうですが、そういうのはまだ先の話っぽいので、ひとまずこれで。