テストの構造化とリファクタリング
June 22, 2023
この記事は、次の動画で解説されている「テストの構造化とリファクタリング」の部分からの引用です。
- TDD Boot Camp 2020 Online - YouTube
- https://www.youtube.com/live/Q-FJ3XmFlT8?feature=share&t=7005
テストの構造化とリファクタリング #
*言語は Java です。なおこのコードは動画のものから一部改変があります。
テスト対象のコード #
public class FizzBuzz {
public String convert(int num) {
if (num % 3 == 0 && num % 5 == 0) {
return "FizzBuzz";
}
if (num % 3 == 0) {
return "Fizz";
}
if (num % 5 == 0) {
return "Buzz";
}
return String.valueOf(num);
}
}
構造化・リファクタリングの前 #
class FizzBuzzTest {
private FizzBuzz fizzbuzz;
@BeforeEach
void 前準備() {
fizzbuzz = new FizzBuzz();
}
@Test
void _1を渡すと文字列1を返す() throws Exception {
assertEquals("1", fizzbuzz.convert(1));
}
@Test
void _2を渡すと文字列2を返す() throws Exception {
assertEquals("2", fizzbuzz.convert(2));
}
@Test
void _3を渡すと文字列Fizzを返す() throws Exception {
assertEquals("Fizz", fizzbuzz.convert(3));
}
@Test
void _5を渡すと文字列Buzzを返す() throws Exception {
assertEquals("Buzz", fizzbuzz.convert(5));
}
@Test
void _15を渡すと文字列FizzBuzzを返す() throws Exception {
assertEquals("FizzBuzz", fizzbuzz.convert(15));
}
}
問題点
- テストコードが「動作する “ドキュメント”」になっていない。
- テストコードのコメントを見ればコードの具体的な振る舞いは読み取れる。しかし FizzBuzz とはいったい何者で、他の数を渡した場合はどのように動作するべきなのかが伝わらない。
- 結局 FizzBuzz の実装クラスのコードを見て初めて、3の倍数なら Fizz を、5の倍数なら Buzz を… といったことを理解することができる。
- 必要最小限なテストになっていない。
- 「_1 を渡すと文字列 1 を返す」と「_2 を渡すと文字列 2 を返す」のどちらかは無駄。
- 実はテスト作成者が作業の過程で結果として2つのテストを書いただけだが、それは他人にはわからない。
構造化・リファクタリングの後 #
@DisplayName("Fizz Buzz 数列と変換規則を扱う FizzBuzz クラス")
class FizzBuzzTest {
private FizzBuzz fizzbuzz;
@BeforeEach
void 前準備() {
fizzbuzz = new FizzBuzz();
}
@Nested
class convertメソッドは数を文字列に変換する {
@Nested
class _3の倍数のときは数の代わりにFizzに変換する {
@Test
void _3を渡すと文字列Fizzを返す() throws Exception {
assertEquals("Fizz", fizzbuzz.convert(3));
}
}
@Nested
class _5の倍数のときは数の代わりにBuzzに変換する {
@Test
void _5を渡すと文字列Buzzを返す() throws Exception {
assertEquals("Buzz", fizzbuzz.convert(5));
}
}
@Nested
class _3と5の倍数のときは数の代わりにFizzBuzzに変換する {
@Test
void _15を渡すと文字列FizzBuzzを返す() throws Exception {
assertEquals("FizzBuzz", fizzbuzz.convert(15));
}
}
@Nested
class その他の数のときはそのまま文字列に変換する {
@Test
void _1を渡すと文字列1を返す() throws Exception {
assertEquals("1", fizzbuzz.convert(1));
}
// 👇 削除
// @Test
// void _2を渡すと文字列2を返す() throws Exception {
// assertEquals("2", fizzbuzz.convert(2));
// }
}
}
}
改善点
- テストコードが「動作する “ドキュメント”」になっている。
- テストコードのコメントを見れば、実装コードの仕様が伝わるものになった。
- 必要最小限なテストになっている。
- テストのメンテナンスコストが最小限になった。