Featured image of post MooによるTDD講座 #1 - 環境構築とはじめてのテスト駆動開発

MooによるTDD講座 #1 - 環境構築とはじめてのテスト駆動開発

Test2とMooを使った開発環境をDockerで構築し、TDDの基本サイクル「レッド→グリーン→リファクタリング」を体験します。まずは失敗するテストを書くことから始めましょう。

はじめに

テスト駆動開発(TDD: Test-Driven Development)は、「テストを先に書いてから実装する」開発手法です。コードの品質を保ちながら、安心してリファクタリングできる環境を作ります。

この連載では、PerlのモダンなオブジェクトシステムであるMooと、強力なテストフレームワークTest2を使って、TDDの基本から実践的なテクニックまでを学んでいきます。

対象読者

  • Perlの基本構文を理解している方
  • オブジェクト指向プログラミングに興味がある方
  • テストを書いたことがない、または少ししか経験がない方
  • 「テストを先に書く」という発想に興味がある方

この記事では、環境構築から最初のテストまでを一緒に体験していきましょう。

環境構築(サクッと動かす)

まずは、すぐに試せる開発環境を整えます。Dockerを使えば、ローカル環境を汚さずに始められます。

リポジトリの作成

プロジェクト用のディレクトリを作成しましょう。

1
2
3
mkdir moo-tdd-tutorial
cd moo-tdd-tutorial
git init

Dockerfileの準備

以下の内容でDockerfileを作成します。Perl 5.38の公式イメージをベースに、必要なモジュールをインストールします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
FROM perl:5.38

WORKDIR /app

# cpanmのインストール
RUN cpanm App::cpanminus --notest

# cpanfileをコピーして依存関係をインストール
COPY cpanfile .
RUN cpanm --installdeps . --notest

# アプリケーションコードをコピー
COPY . .

CMD ["bash"]

cpanfileでの依存管理

プロジェクトで使用するモジュールをcpanfileで管理します。

1
2
3
4
requires 'Moo', '2.005004';
requires 'Test2::V0', '0.000145';
requires 'Test2::Tools::Explain';
requires 'strictures', '2';

Mooは軽量で高速なオブジェクトシステム、Test2::V0はモダンなテストツールキットです。

compose.yamlの作成

開発を楽にするため、compose.yamlも用意しましょう。

1
2
3
4
5
6
7
8
9
services:
  app:
    build: .
    volumes:
      - .:/app
    working_dir: /app
    command: bash
    stdin_open: true
    tty: true

動作確認

環境が正しくセットアップできたか確認します。

1
2
docker compose build
docker compose run --rm app perl -v

Perlのバージョン情報が表示されれば成功です。

1
docker compose run --rm app cpanm --version

cpanmが正常に動作していることも確認しておきましょう。

TDDの基本サイクルを体験

TDDには「レッド→グリーン→リファクタリング」という基本サイクルがあります。

レッド:失敗するテストを書く

まず、実装がまだ存在しない状態でテストを書きます。当然、このテストは失敗します(赤=Red)。この段階で「何を作るべきか」を明確にします。

グリーン:最小限の実装で通す

次に、テストを通すための最小限のコードを書きます。テストが成功すれば緑(Green)になります。「きれいなコード」ではなく「動くコード」を最優先します。

リファクタリング:コードをきれいにする

テストが通った状態で、コードを整理します。テストがあるので、壊していないか常に確認できます。

このサイクルを小刻みに繰り返すことで、品質の高いコードを安全に作り上げていきます。

実践:Personクラスを作ってみる

それでは、実際にTDDでシンプルなPersonクラスを作ってみましょう。

プロジェクト構造の準備

まず、ディレクトリ構造を整えます。

1
mkdir -p lib t
  • lib/: アプリケーションコードを配置
  • t/: テストコードを配置

ステップ1:失敗するテストを書く(レッド)

t/01-person.tを作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
use strict;
use warnings;
# Personクラスをテストする宣言
use Test2::V0 -target => 'Person';

# Personオブジェクトが作成できることをテスト
my $person = Person->new(name => 'Alice');
ok $person, 'Person object created';

# nameアトリビュートが正しく取得できることをテスト
is $person->name, 'Alice', 'name attribute works';

done_testing;

このテストを実行してみましょう。

1
docker compose run --rm app prove -lv t/01-person.t

当然、Personクラスがまだ存在しないので、テストは失敗します。これが「レッド」の状態です。

ステップ2:最小限の実装で通す(グリーン)

lib/Person.pmを作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package Person;
use Moo;
use strictures 2;

has name => (
    is => 'ro',
    required => 1,
);

1;

Mooのhasキーワードでnameアトリビュートを定義しました。

  • is => 'ro': 読み取り専用(read-only)
  • required => 1: 必須パラメータ

再度テストを実行します。

1
docker compose run --rm app prove -lv t/01-person.t

今度は全てのテストが通るはずです。これが「グリーン」の状態です!

ステップ3:リファクタリング

今回のコードは非常にシンプルなので、リファクタリングの必要はほとんどありません。しかし、例えばテストに説明を追加するなどの改善ができます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
use strict;
use warnings;
use Test2::V0 -target => 'Person';

subtest 'Person class basic functionality' => sub {
    my $person = Person->new(name => 'Alice');
    ok $person, 'Person object created successfully';

    is $person->name, 'Alice', 'name attribute returns correct value';
};

done_testing;

subtestを使うことで、テストをグループ化して読みやすくできます。

全体のテスト実行

プロジェクト全体のテストを実行するには、以下のコマンドを使います。

1
docker compose run --rm app prove -lr t/
  • -l: lib/ディレクトリをインクルードパスに追加
  • -r: t/ディレクトリ以下を再帰的に実行

まとめと次回予告

TDDの心構え

今回、私たちは以下のサイクルを体験しました。

  1. レッド:まずテストを書いて失敗させる
  2. グリーン:最小限の実装でテストを通す
  3. リファクタリング:コードを改善する

TDDの本質は「テストファースト」だけではありません。小さなステップで進むことが重要です。一度に多くを実装しようとせず、1つのテストを通すことに集中しましょう。

今回学んだこと

  • DockerでのPerl + Moo + Test2環境の構築
  • TDDの基本サイクル(レッド→グリーン→リファクタリング)
  • Mooでの基本的なクラス定義
  • Test2::V0を使った基本的なテストの書き方

次回予告

次回は「MooによるTDD講座 #2 - メソッドのテストとTest2の機能」として、以下の内容を扱います。

  • メソッドの追加とテスト
  • Test2の便利な機能(like, match, arrayなど)
  • 例外処理のテスト
  • テストの構造化とサブテスト

お楽しみに!

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。