Typescript で Document Testing したい
TypeScriptを使用している開発者であれば、コードにドキュメントを書いた人もいるかと思います。
ドキュメントに対して、ドキュメントテストというのが書けるらしいです。
この記事では、TypeScriptでドキュメントテストを行うためのツールをいくつか紹介します。
サンプルコードは、以下にあります。
https://github.com/silverbirder/playground
Document Testingとは?
ドキュメントテストとは、JSDocやTSDocのコメントを利用して、コード上にドキュメントを記述し、
そのドキュメント内のコードサンプルを実際にテストすることです。
このアプローチにより、ドキュメントが常に最新の状態に保たれ、コードの使用方法が正確に反映されるようになります。
ただし、JavaScriptやTypeScript自体にはこの機能が組み込まれていないため、外部のライブラリを使用する必要があります。
Deno では公式に Documentation Tests が用意されているようです。素晴らしいですね。
試したツール
私が試したツールは以下の3つです。
-
doctest-ts
- コード内のコメントからテストコードを生成し、Jestを使用して実行します。
- Jest以外のテストツールも選択可能です
- コード内のコメントからテストコードを生成し、Jestを使用して実行します。
-
tsdoc-testify
- TSDocコメントからテストコードを生成し、Nodejsのassertモジュールでテストを実行します。
-
the-real-doctest
- TSDocコメント内で直接テストを記述し、独自のコマンドでテストを実行します。
また、doc-vitestも魅力的に見えましたが、今回は検証から除外しました。
各ツールの使い方
doctest-ts
doctest-tsは、特定のフォーマットでコメントにテストケースを記述することで、テストを簡単に追加できます。
ドキュメントは、以下のように書きます。
// src/hasFoo.ts
/** Does this string contain foo, ignoring case?
hasFoo('___foo__') // => true
hasFoo(' fOO ') // => true
hasFoo('Foo.') // => true
hasFoo('bar') // => false
hasFoo('fo') // => false
hasFoo('oo') // => false
*/
function hasFoo(s: string): boolean {
return null != s.match(/foo/i);
}
以下のコマンドを使用してテストファイルを生成し、Jestでテストを実行できます。
doctest-ts --jest src/hasFoo.ts
生成されたテストコードは以下です。
/** Does this string contain foo, ignoring case?
hasFoo('___foo__') // => true
hasFoo(' fOO ') // => true
hasFoo('Foo.') // => true
hasFoo('bar') // => false
hasFoo('fo') // => false
hasFoo('oo') // => false
*/
function hasFoo(s: string): boolean {
return null != s.match(/foo/i);
}
import "jest"
const __expect: jest.Expect = expect
describe("hasFoo", () => {
it("hasFoo", () => {
__expect(hasFoo("___foo__")).toEqual(true)
__expect(hasFoo(" fOO ")).toEqual(true)
__expect(hasFoo("Foo.")).toEqual(true)
__expect(hasFoo("bar")).toEqual(false)
__expect(hasFoo("fo")).toEqual(false)
__expect(hasFoo("oo")).toEqual(false)})
})
tsdoc-testify
tsdoc-testifyは、TSDocコメント内にテストケースを記述し、Nodeのassertモジュールを使用してテストを実行します。
ドキュメントは、以下のように書きます。
// ./src/sub.ts
/**
* sub function
*
* @remarks
* demo
*
* @example
*
* ```
* import * as assert from "assert";
* import { sub } from "./sub";
*
* assert.equal(sub(2, 1), 1);
* ```
*
* @example
*
* ```
* import * as assert from "assert";
* import { sub } from "./sub";
*
* assert.equal(sub(4, 5), -1);
* ```
* @param a
* @param b
*/
export function sub(a: number, b: number) {
return a - b;
}
テストケースは以下のコマンドで生成されます。
tsdoc-testify --filepath ./src/sub.ts
生成されたテストコードは以下です。
// Code generated by "tsdoc-testify"; DO NOT EDIT.
import * as assert from "assert";
import { sub } from "./sub";
test("/<path_to_app>/src/sub.ts_0", () => {
assert.equal(sub(2, 1), 1);
});
test("/<path_to_app>/src/sub.ts_1", () => {
assert.equal(sub(4, 5), -1);
});
the-real-doctest
the-real-doctestは、TSDocコメント内で直接テストを記述し、独自のコマンドを使用してテストを実行します。
これはテストコードの生成を省略し、シンプルな比較演算子(==, !=, === or !==
)を使用してテストを記述できます。
ドキュメントは、以下のように書きます。
// ./src/nsum.ts
/**
* @param n
* @returns the sum of the n first integers
* @example
* const n = 5
* const expected = 1 + 2 + 3 + 4 + 5
* const actual = nsum(n)
* actual == expected
* @example nsum(3) == 1 + 2 + 3
* @example nsum(8) == 36 // This should fail
*/
function nsum(n: number): number {
return (n * (n + 1)) / 2;
}
以下のコマンドで、テストを実行できます。
the-real-doctest test ./src/nsum.ts
結論
ドキュメントテストは、コードの使用方法を明確に理解し、ドキュメントを最新の状態に保つのに非常に役立ちます。
開発エディタのコード補完を使えば、コード内部を読まなくても使い方の理解が深まります。
個人的には、Denoのドキュメントテスト機能が最も興味深いと感じましたが、選択はプロジェクトのニーズや好みによって異なるでしょう。
ドキュメントテストを積極的に利用して、より良いコードベースを目指しましょう!
Discussion