音の鳴るブログ

鳴らないこともある

乱数を使う関数のテスト

function coin(x) {
  return Math.random() < x;
}

こういう関数があったとして、どうテストを書くのか。

ぱっと思いつくのはこういう感じで、Math.random 自体を上書きするやり方。

describe("coin(x)", function() {
  it("works", sinon.test(function() {
    this.stub(Math, "random", function() {
      return 0.5;
    });

    assert(coin(0.4) === false);
    assert(coin(0.5) === false);
    assert(coin(0.6) === true);
  }));
});

このやり方、たしかに間違っていないんだけど、関数のインターフェース自体を変更した方が良いと思う。

function coin(x, random) {
  random = random || Math.random;
  return random() < x;
}

これだとテストがしやすいだけじゃなく、偏った乱数生成器とかシード付きの乱数生成器を使用したりできて便利さ100万倍になる。

describe("coin(x)", function() {
  it("works", function() {
    var random = function() {
      return 0.5;
    };
    
    assert(coin(0.4, random) === false);
    assert(coin(0.5, random) === false);
    assert(coin(0.6, random) === true);
  });
});

参照