2014年1月3日金曜日

CodeIQ MAGAZINE「現在時刻が関わるテストから、テスト容易性設計を学ぶ」を解いてみた

CodeIQ MAGAZINE これであなたもテスト駆動開発マスター!?和田卓人さんがテスト駆動開発問題を解答コード使いながら解説します~現在時刻が関わるテストから、テスト容易性設計を学ぶ #tdd

読んでみたら、参加言語とアプローチの内訳に、Javaで「現在時刻を引数で渡す」アプローチがなかったので、書いてみました。

以下は実装です。
package tdd;

import java.util.Calendar;
import java.util.Date;

/**
 * 挨拶をするクラスです。
 * @author michigawi
 */
public class Greeter {

 /**
  * 挨拶します。
  * @param date 日時
  * @return 挨拶
  */
 public String greet(Date date) {
  Calendar cal = Calendar.getInstance();
  cal.setTime(date);

  int hour = cal.get(Calendar.HOUR_OF_DAY);
  int minute = cal.get(Calendar.MINUTE);
  int second = cal.get(Calendar.SECOND);

  for (Greeting greeting : Greeting.values()) {
   if (greeting.valid(hour, minute, second)) {
    return greeting.getGreeting();
   }
  }

  return null;
 }

 /**
  * 挨拶です。
  * @author michigawi
  */
 private enum Greeting {
  /** 朝 */
  MORNING("おはようございます") {
   @Override
   public boolean valid(int hour, int minute, int second) {
    if (hour >= 5 && (hour <= 11 && minute <= 59 && second <= 59)) {
     return true;
    }

    return false;
   }
  }
  /** 日中 */
  , AFTERNOON("こんにちは") {
   @Override
   public boolean valid(int hour, int minute, int second) {
    if (hour >= 12 && (hour <= 17 && minute <= 59 && second <= 59)) {
     return true;
    }

    return false;
   }
  }
  /** 夜 */
  , NIGHT("こんばんは") {
   @Override
   public boolean valid(int hour, int minute, int second) {
    if (hour >= 18 && (hour <= 23 && minute <= 59 && second <= 59)) {
     return true;
    }

    if (hour >= 0 && (hour <= 4 && minute <= 59 && second <= 59)) {
     return true;
    }

    return false;
   }
  };

  /** 挨拶するか */
  public abstract boolean valid(int hour, int minute, int second);

  /** 挨拶 */
  private String greeting;

  /**
   * コンストラクタです。
   * @param greeting
   */
  Greeting(String greeting) {
   this.greeting = greeting;
  }

  /**
   * 挨拶を返します。
   * @return 挨拶
   */
  public String getGreeting() {
   return greeting;
  }
 }
}
最後にテストです。
package tdd;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.util.Calendar;

import org.junit.Before;
import org.junit.Test;

/**
 * {@link tdd.Greeter}のテストです。
 * @author michigawi
 */
public class GreeterTest {

 /** テスト対象のクラス */
 private Greeter greeter;

 /** カレンダー */
 private Calendar calendar;

 /**
  * setup.
  */
 @Before
 public void setUp() {
  greeter = new Greeter();
  calendar = Calendar.getInstance();
  calendar.clear();
  calendar.set(2014, Calendar.JANUARY, 3);
 }

 /**
  * Test method for {@link tdd.Greeter#greet(java.util.Date)}.
  */
 @Test
 public void 午前0時ジャストはこんばんは() {
  calendar.set(Calendar.HOUR_OF_DAY, 0);
  calendar.set(Calendar.MINUTE, 0);
  calendar.set(Calendar.SECOND, 0);
  assertThat("", greeter.greet(calendar.getTime()), is("こんばんは"));
 }

 /**
  * Test method for {@link tdd.Greeter#greet(java.util.Date)}.
  */
 @Test
 public void 午前5時より前はこんばんは() {
  calendar.set(Calendar.HOUR_OF_DAY, 4);
  calendar.set(Calendar.MINUTE, 59);
  calendar.set(Calendar.SECOND, 59);
  assertThat("", greeter.greet(calendar.getTime()), is("こんばんは"));
 }

 /**
  * Test method for {@link tdd.Greeter#greet(java.util.Date)}.
  */
 @Test
 public void 午前5時ジャストはおはようございます() {
  calendar.set(Calendar.HOUR_OF_DAY, 5);
  calendar.set(Calendar.MINUTE, 0);
  calendar.set(Calendar.SECOND, 0);
  assertThat("", greeter.greet(calendar.getTime()), is("おはようございます"));
 }

 /**
  * Test method for {@link tdd.Greeter#greet(java.util.Date)}.
  */
 @Test
 public void 正午の前はおはようございます() {
  calendar.set(Calendar.HOUR_OF_DAY, 11);
  calendar.set(Calendar.MINUTE, 59);
  calendar.set(Calendar.SECOND, 59);
  assertThat("", greeter.greet(calendar.getTime()), is("おはようございます"));
 }

 /**
  * Test method for {@link tdd.Greeter#greet(java.util.Date)}.
  */
 @Test
 public void 正午はこんにちは() {
  calendar.set(Calendar.HOUR_OF_DAY, 12);
  calendar.set(Calendar.MINUTE, 0);
  calendar.set(Calendar.SECOND, 0);
  assertThat("", greeter.greet(calendar.getTime()), is("こんにちは"));
 }

 /**
  * Test method for {@link tdd.Greeter#greet(java.util.Date)}.
  */
 @Test
 public void 午後6時より前はこんにちは() {
  calendar.set(Calendar.HOUR_OF_DAY, 17);
  calendar.set(Calendar.MINUTE, 59);
  calendar.set(Calendar.SECOND, 59);
  assertThat("", greeter.greet(calendar.getTime()), is("こんにちは"));
 }

 /**
  * Test method for {@link tdd.Greeter#greet(java.util.Date)}.
  */
 @Test
 public void 午後6時ジャストはこんばんは() {
  calendar.set(Calendar.HOUR_OF_DAY, 18);
  calendar.set(Calendar.MINUTE, 0);
  calendar.set(Calendar.SECOND, 0);
  assertThat("", greeter.greet(calendar.getTime()), is("こんばんは"));
 }

 /**
  * Test method for {@link tdd.Greeter#greet(java.util.Date)}.
  */
 @Test
 public void _24時はこんばんは() {
  calendar.set(Calendar.HOUR_OF_DAY, 24);
  calendar.set(Calendar.MINUTE, 0);
  calendar.set(Calendar.SECOND, 0);
  assertThat("", greeter.greet(calendar.getTime()), is("こんばんは"));
 }
}

様々なアプローチがあるんだなぁと思いました。