5月28日

投稿者: | 2020年5月28日

テストがエラーの状態で終わらせたので、まずはテストを実行してみる。
「想定外のお金を投入する」テストがエラーになるので、ここから作業を再開する。

	@Test
	void 想定外のお金を投入() {
		VendingMachine vm = new VendingMachine();
		vm.put(5);
		int m = vm.entered();
		assertEquals(0, m);
		vm.put(1);
		m = vm.entered();
		assertEquals(0, m);
		for (int i = 1; i <= 10000; i++) {
			vm.put(i);
			m = vm.entered();
			if (i == 10 || i == 50 || i == 100 || i == 500 || i == 1000) {
				assertEquals(i, m);
			} else {
				assertEquals(0, m);
			}
			vm.refund();
		}
	}

VendingMachineに実装を追加する。

	/**
	 * 10円玉、50円玉、100円玉、500円玉、1000円札だけ扱える
	 * @param money
	 */
	public void put(int money) {
		if (money == 10 || money == 50 || money == 100 || money == 500 || money == 1000) {
			total += money;
		}
	}

ステップ2 ジュースの管理

値段と名前の属性からなるジュースを1種類格納できる。初期状態で、コーラ(値段:120円、名前”コーラ”)を5本格納している。
格納されているジュースの情報(値段と名前と在庫)を取得できる。

Juiceクラスを新規作成する。

package jp.abc;

public class Juice {
	private String name;
	private int price;

	public Juice() {
		this(null, 0);
	}
	public Juice(String name, int price) {
		this.name = name;
		this.price = price;
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getPrice() {
		return price;
	}
	public void setPrice(int price) {
		this.price = price;
	}
}

VendingMachineTestにテストを追加する。

	@Test
	void コーラの在庫確認() {
		VendingMachine vm = new VendingMachine();
		List<Juice> list = vm.getJuiceList();
	}

コンパイルエラーを解消するために、クイックフィックスでVendingMachineクラスにgetJuiceList()メソッドを作成する。

	public List<Juice> getJuiceList() {
		return null;
	}

まずはFakeでNullPointerExceptionを解消する。

	public List<Juice> getJuiceList() {
		return new ArrayList<Juice>();
	}

テストにパスするように実装してみる。

	public List<Juice> getJuiceList() {
		List<Juice> list = new ArrayList<Juice>();
		list.add(new Juice());
		return list;
	}

ジュースの名前の確認でエラーになるのを解消するために、VendingMachineを修正する。

	public List<Juice> getJuiceList() {
		List<Juice> list = new ArrayList<Juice>();
		list.add(new Juice("コーラ", 120));
		return list;
	}

コーラの在庫確認で、値段も確認するコードを追加する。

	@Test
	void コーラの在庫確認() {
		VendingMachine vm = new VendingMachine();
		List<Juice> list = vm.getJuiceList();
		assertEquals(1, list.size());
		Juice juice = list.get(0);
		assertEquals("コーラ", juice.getName());
		assertEquals(120, juice.getPrice());
	}

在庫確認のためのテストを追加する。

	@Test
	void コーラの在庫確認() {
		VendingMachine vm = new VendingMachine();
		List<Juice> list = vm.getJuiceList();
		assertEquals(1, list.size());
		Juice juice = list.get(0);
		assertEquals("コーラ", juice.getName());
		assertEquals(120, juice.getPrice());
		boolean b = vm.isStock("コーラ");
		assertEquals(true, b);
	}

VendingMachineにisStock()メソッドをクイックフィックスで追加する。

	public boolean isStock(String name) {
		return false;
	}

これでテストを実行すると、エラーになる。

fakeでテストにパスするように修正する。

	public boolean isStock(String name) {
		return true;
	}

ステップ3 購入

投入金額、在庫の点で、コーラが購入できるかどうかを取得できる。
ジュース値段以上の投入金額が投入されている条件下で購入操作を行うと、ジュースの在庫を減らし、売り上げ金額を増やす。
投入金額が足りない場合もしくは在庫がない場合、購入操作を行っても何もしない。
現在の売上金額を取得できる。
払い戻し操作では現在の投入金額からジュース購入金額を引いた釣り銭を出力する。

コーラが購入できるかどうかを取得できるようにする。
まずテストを追加する。

	@Test
	void コーラが購入できるかどうかを取得する() {
		VendingMachine vm = new VendingMachine();
		boolean b = vm.canBuy("コーラ");
		assertEquals(false, b);
	}

クイックフィックスでcanBuy()メソッドをVendingMachineに追加する。

	public boolean canBuy(String name) {
		return false;
	}

テストで500円を投入してコーラを購入できるようにする。

	@Test
	void コーラが購入できるかどうかを取得する() {
		VendingMachine vm = new VendingMachine();
		boolean b = vm.canBuy("コーラ");
		assertEquals(false, b);
		vm.put(500);
		b = vm.canBuy("コーラ");
		assertEquals(true, b);
	}

120円以上投入されていればtrueを返すように修正する。
これでテストにパスできる。

	public boolean canBuy(String name) {
		if (total >= 120) return true;
		return false;
	}

コーラを購入する操作をテストに追加する。

	@Test
	void コーラが購入できるかどうかを取得する() {
		VendingMachine vm = new VendingMachine();
		boolean b = vm.canBuy("コーラ");
		assertEquals(false, b);
		vm.put(500);
		b = vm.canBuy("コーラ");
		assertEquals(true, b);
		Juice j = vm.buy("コーラ");
		assertEquals("コーラ", j.getName());
	}

クイックフィックスでbuy()メソッドをVendingMachineに追加する。
テストを実行するとNullPointerExceptionが発生する。

	public Juice buy(String name) {
		return null;
	}

テストにパスするように修正する。

	public Juice buy(String name) {
		return new Juice("コーラ", 120);
	}

コーラを購入したら投入金額が120円減って380円になるテストを追加する。

	@Test
	void コーラを購入する() {
		VendingMachine vm = new VendingMachine();
		vm.put(500);
		Juice j = vm.buy("コーラ");
		assertEquals("コーラ", j.getName());
		int m = vm.entered();
		assertEquals(380, m);
	}

fakeでテストにパスするように修正する。

	public Juice buy(String name) {
		total = 380;
		return new Juice("コーラ", 120);
	}

2本目のコーラを購入したらテストがエラーになる。

	@Test
	void コーラを購入する() {
		VendingMachine vm = new VendingMachine();
		vm.put(500);
		Juice j = vm.buy("コーラ");
		assertEquals("コーラ", j.getName());
		int m = vm.entered();
		assertEquals(380, m);
		j = vm.buy("コーラ");
		m = vm.entered();
		assertEquals(260, m);
	}

コーラを在庫切れにするテストを追加する。

	@Test
	void コーラを在庫切れにする() {
		VendingMachine vm = new VendingMachine();
		vm.put(1000);
		for (int i = 0; i < 5; i++) {
			Juice j = vm.buy("コーラ");
			assertEquals("コーラ", j.getName());
		}
		int m = vm.entered();
		assertEquals(400, m);
		boolean b = vm.canBuy("コーラ");
		assertEquals(false, b);
	}

コーラを在庫切れにするテストにパスするように、在庫を管理するコードをVendingMachineに追加する。

package jp.abc;

import java.util.ArrayList;
import java.util.List;


/**
 * 自動販売機クラス
 * @author satoshis
 *
 */
public class VendingMachine {

	private int total = 0;
	private int stock = 5;

	/**
	 * 10円玉、50円玉、100円玉、500円玉、1000円札だけ扱える
	 * @param money
	 */
	public void put(int money) {
		if (money == 10 || money == 50 || money == 100 || money == 500 || money == 1000) {
			total += money;
		}
	}

	public int entered() {
		return total;
	}

	public int refund() {
		int r = total;
		total = 0;
		return r;
	}

	public List<Juice> getJuiceList() {
		List<Juice> list = new ArrayList<>();
		list.add(new Juice("コーラ", 120));
		return list;
	}

	public boolean isStock(String name) {
		return true;
	}

	public boolean canBuy(String name) {
		// 在庫切れはfalseを返す
		if (stock == 0) return false;
		if (total >= 120) return true;
		return false;
	}

	public Juice buy(String name) {
		total -= 120;
		stock--;
		return new Juice("コーラ", 120);
	}

}

ステップ4 機能拡張

ジュースを3種類管理できるようにする。
在庫にレッドブル(値段:200円、名前”レッドブル”)5本を追加する。
在庫に水(値段:100円、名前”水”)5本を追加する。
投入金額、在庫の点で購入可能なドリンクのリストを取得できる。

レッドブルと水を購入できるようにするためのテストを追加する。

	@Test
	void ジュースの種類を増やす() {
		VendingMachine vm = new VendingMachine();
		List<Juice> list = vm.getJuiceList();
		assertEquals(3, list.size());
	}

VendingMachineのgetJuiceList()メソッドを修正する。

	public List<Juice> getJuiceList() {
		List<Juice> list = new ArrayList<>();
		list.add(new Juice("コーラ", 120));
		list.add(new Juice("レッドブル", 200));
		list.add(new Juice("水", 100));
		return list;
	}

そうすると、「コーラの在庫確認」テストがエラーになる。
「コーラの在庫確認」テストの在庫数を3に変更してテストをパスさせる。

	@Test
	void コーラの在庫確認() {
		VendingMachine vm = new VendingMachine();
		List<Juice> list = vm.getJuiceList();
		assertEquals(1, list.size());
		Juice juice = list.get(0);
		assertEquals("コーラ", juice.getName());
		assertEquals(120, juice.getPrice());
		boolean b = vm.isStock("コーラ");
		assertEquals(true, b);
	}

100円入れたら水が買えるはずなので、テストを追加する。

	@Test
	void ジュースの種類を増やす() {
		VendingMachine vm = new VendingMachine();
		List<Juice> list = vm.getJuiceList();
		assertEquals(3, list.size());
		vm.put(100);
		boolean b = vm.canBuy("水");
		assertEquals(true, b);
	}