文章のテスト

技術書とかの文書を開発するにあたってテストを先に書きたくなったという話です。

とかの続きみたいなものです。

ここで扱う文章は、Markdownですが、構造を持った文章なら多分適応できる気がします。 具体的にはtextlintで扱うパーサを再利用しているので、reStructuredTextとかRe:VIEWとかHTMLも多分頑張ればできる。

構造化された文章

構造を持った文章とはどういうものかというと、セクションやパラグラフなどがシンタックスとして大体分かる文章の事をここでは言っています。

しかし、Markdownにはセクション(HTMLでは <section> タグに該当するもの)がないので、HeaderとHeaderの間を一つのセクションとして認識しています。

文章が特定のキーワードを含むかテストする

実際どうやって文章をテストするかというと次のようなBDDっぽいようなテストを書きます。

このテストではサンプルというワードを含むセクションが、 単語というキーワードを含んでいるかをテストしています。

** で囲んだ範囲だけをキーワードの対象にできます。

const tester = require("text-testing-mocha");
const fs = require("fs");
// テストする対象の文章を読み込む
const content = fs.readFileSync("README.md", "utf-8");
tester(content, (section) => {
    // 指定したセクションが
    section("この**サンプル**が", (test) => {
        test("この**単語**を含んでいるかをテストする");
    });
});

例えば次の文章だと、先ほどのテストはパスします。

# サンプルA

ある単語を含んでいる文章なのでOK

しかし、次の文章だと、先ほどのテストは失敗します。

# サンプルB

ある???を含んでいないのでダメ

デフォルトでは含んでいる事をテストしていますが、第二引数で任意の判定をかけるので、含まない事も書くことができます。

tester(content, (section) => {
    section("ある**サンプル**は", (it, sections) => {
        it("**unknown**を含まない", (texts, section) => {
            return texts.every(text => !section.contains(text));
        });
    });
});

text-testing-mochaは名前の通り、Mochaを使って動くDSLみたいなものです。

正直すごい雑で大したことをやっていないです。

モチベーション

asciidwango/js-primer: JavaScriptの入門書を書いていて、一つの章が長くなると目的を見失う事がままあります。

そのため、まずその章が何を説明したいのかという目標規定文を書き、書きながらそれを何度も見なおして脇道に逸れないように注意を払う必要がありました。

章やセクションと言った単位で書いてる途中で、その目標が変わることはあまりないはずなので、何かガイドとなるものが欲しかったのが一つのモチベーションです。

テストファースト

新しい文章を書いてて一番気が重たいのは最初の一行を書くことだと思います。 しかし、アウトラインは本文に比べてラクな気持ちで書くことができていました。

なので、最初にアウトラインをテストとして書いてみることから始めました。 そうすることで、テストが落ちます。

テストが落ちてるので、次はテストが通るように文章を書き始めれば良くなります。 そうすることで、書き始めが楽になるのではないかなという実験も兼ねて作り始めました。

it("2000年は閏年", () => {
    assert(isLeap(2000));
});

というテストを書いて、

function isLeap(year) {
    return year % 4 === 0;
}

というコードから書き始めるのと同じような気分でスタートできます。

また、技術書のような文書はある程度文章の構造があると思うので、入力(文章)に対する出力(伝えたい結果)はテストできてもいいんじゃないかなという期待も持っています。

実際にこのテストを取り入れて書いてみたものは次のものになっています。

後は、何かと文章は一度に多くを書きすぎてしまう問題を持っている気がします。 小さなPull Requestして開発を進めるのがいいように、文章にも同じアプローチが正しいのかは今後検証していきたい気がします。 この時に、より"構造"というものを意識した書き方が必要になるのかもしれません。

分かりやすいコードも分かりやすい文章もある程度のレベルまでは、センスとかではなく技術的なアプローチで解決できる問題なのではないかなと考えています。