名古屋アジャイル勉強会のTDDワークショップ

名古屋アジャイル勉強会でテスト駆動開発の体験ワークショップを行いました。
僕はスタッフとして、テスト駆動開発の簡単な解説をしたのと、ペアプロC言語でstackを実装するのをやりました。

テスト駆動開発の説明は、t-wadaさんの資料(プレゼンや動画)がwebで見られるので、わざわざ作るまでもない気もしましたが、資料借用して済ませるのもまずいと思い、簡単なものを作りました。テスト駆動開発とは、今から書こうとする数行のコードの意図を、まずテストという形で表明する、というやり方のプログラミング技法です、と説明しました。テストの価値、品質との関係、などは、僕からは説明せずにみんなで考えてみましょう、みたいな話にしちゃいました。

そのあとorphiriaさんとペアで書いたコードは以下の通りです。

makefile
all:
	gcc -Wall -g -c *.c
	g++ -Wall -g -c *.cpp
	g++ -Wall -o a.out *.o
	./a.out

こりゃいちじるしくなんちゃってですね。

unittest.h

このヘルパマクロのヘッダファイルだけは、事前に用意しておきました。これは僕はよく使っているものです。

#ifndef __UNITTEST_H__
#define __UNITTEST_H__
#include <stdio.h>
#define RUN_TEST(test) \
    do { \
        printf(#test); fflush(stdout); test(); printf("\tOK\n"); \
    } while(0)
#endif
main.cpp
#include "unittest.h"
#include <iostream>
#include "string.h"
using namespace std;

void
test_stack()
{
    struct stack a_stack;

    init(&a_stack);
    assert(0 == stack_size(&a_stack));

    stack_push(&a_stack, 100);
    assert(1 == stack_size(&a_stack));
    assert(100 == stack_pop(&a_stack));
    assert(0 == stack_size(&a_stack));

    stack_push(&a_stack, 200);
    assert(1 == stack_size(&a_stack));
    assert(200 == stack_pop(&a_stack));
    assert(0 == stack_size(&a_stack));

    stack_push(&a_stack, 300);
    assert(1 == stack_size(&a_stack));
    stack_push(&a_stack, 400);
    assert(2 == stack_size(&a_stack));
    assert(400 == stack_pop(&a_stack));
    assert(1 == stack_size(&a_stack));
    assert(300 == stack_pop(&a_stack));
    assert(0 == stack_size(&a_stack));
}

int
main(int argc, const char * argv[])
{
    RUN_TEST(test_stack);

	cout << "OK" << endl;
	return 0;
}
stack.h
#ifndef STACK_H
#define STACK_H

#include <stdlib.h>

struct stack {
    size_t size;
    int value[2];
};

#endif
stack.c
#include "stack.h"
#include "string.h"

size_t
stack_size(struct stack * a_stack)
{
    return a_stack->size;
}

void
stack_push(struct stack * a_stack, int n)
{
    a_stack->value[a_stack->size] = n;
    ++(a_stack->size);
}

int
stack_pop(struct stack * a_stack)
{
    --(a_stack->size);
    return a_stack->value[a_stack->size];
}

void
init(struct stack * a_stack)
{
    memset(a_stack, 0, sizeof(struct stack));
}

ユニットテスト実行のフレームワーク的なものは、unittest.hに定義したヘルパマクロだけです。assertは標準ライブラリのマクロを使っています。なにかフレームワークを使えばもっと便利ですが、この程度のものでもできるよ、という例ということで。

C言語での実装ですが、テストはC++にしています。上記例ではCでもよかったかしらと思いますが、もうちょっと込み入ったテストになってきたら、RAIIとか使えるC++の方が便利なので。

stack.cの実装は、かなりノーガード戦法な感じですが、とりあえず、テスト駆動でここまで導出できました、ということでご理解ください。用法間違えてエラーになるテストを作って、改善していくのは、今回はできませんでしたけど、時間があったらやるところです。capacityが2固定というのもありえないので、当然見直すところですね。

ともかく、楽しい体験の時間が過ごせました。またぜひ、こういったペアプロテスト駆動開発体験の機会を持ちたいです。