5月24日

前回は、以下のテストを書いたところで終了した。。

	@Test
	void ジュースを3種類管理できる() {
		VendingMachine vm = new VendingMachine();
		vm.put(100);
		boolean b = vm.canBuy("水");
		assertThat(b, is(true));
		b = vm.canBuy("コーラ");
		assertThat(b, is(false));
		b = vm.canBuy("レッドブル");
		assertThat(b, is(false));
	}

テストを実行してエラーになることを確認する。
水を購入できるか問い合わせたところでエラーが発生。

canBuy() メソッドでは、引数で名前をもらっているけど参照していなかった。
ジュースの名前を見て購入可能かを判断するように修正する。

	public boolean canBuy(String name) {
		if (juices.size() == 0) return false;
		return total >= getJuicePrice(name);
	}

getJuicePrice()にも引数を追加して、ジュースの名前を見て価格を返すようにする。

	public int getJuicePrice(String name) {
		if (name.equals("水")) return 100;
		if (name.equals("コーラ")) return 120;
		return 200;
	}

3種類のジュースを購入できるようにしたいので、水を購入するテストを追加する。

	@Test
	void ジュースを3種類購入する() {
		VendingMachine vm = new VendingMachine();
		vm.put(1000);
		Juice j = vm.buy("水");
		assertThat(j.getName(), is("水"));
	}

これまで、1種類(コーラ)しか売ってなかった自動販売機を複数に対応させるのは割と大変。
まずは3種類のジュースを在庫できるようにする。
Mapを追加して、ジュースの名前で在庫を取得できるようにする。

public class VendingMachine {
	private int total;
	private int sales;
	private Map<String, List<Juice>> map = new HashMap<>();
	private List<Juice> juices;

	public VendingMachine() {
		total = 0;
		juices = new ArrayList<>();
		map.put("水", juices);
		for (int i = 0; i < 5; i++) {
			juices.add(new Juice("水", 100));
		}
		juices = new ArrayList<>();
		map.put("コーラ", juices);
		for (int i = 0; i < 5; i++) {
			juices.add(new Juice("コーラ", 120));
		}
		juices = new ArrayList<>();
		map.put("レッドブル", juices);
		for (int i = 0; i < 5; i++) {
			juices.add(new Juice("レッドブル", 200));
		}
	}

テストを実行すると、これまで動いていたテスト「ジュースを購入する()」などでエラーになる。
これはジュースの名前を見ていないのが原因。
ジュースの名前を見て、Mapから在庫を取得するように変更する。

	public Juice buy(String name) {
		if (!canBuy(name)) return null;
		juices = map.get(name);
		Juice j = juices.remove(0);
		total -= j.getPrice();
		sales += j.getPrice();
		return j;
	}

3種類のジュースを購入するテストを書く。

	@Test
	void ジュースを3種類購入する() {
		VendingMachine vm = new VendingMachine();
		vm.put(1000);
		Juice j = vm.buy("水");
		assertThat(j.getName(), is("水"));
		int total = vm.getTotal();
		assertThat(total, is(900));
		int stock = vm.getJuiceStock("水");
		assertThat(stock, is(4));

		j = vm.buy("レッドブル");
		assertThat(j.getName(), is("レッドブル"));
		total = vm.getTotal();
		assertThat(total, is(700));

		j = vm.buy("コーラ");
		assertThat(j.getName(), is("コーラ"));
		total = vm.getTotal();
		assertThat(total, is(580));

		int sales = vm.getSales();
		assertThat(sales, is(420));
	}

getJuiceStock() に引数を追加して、ジュースの名前を指定して在庫を取得できるようにする。

	public int getJuiceStock(String name) {
		return juices.size();
	}

ジュースの名前を見てないのに、getJuiceStock() のテストをパスしているので、怪しい実装を修正するためにテストを追加する。

	@Test
	void ジュースを3種類購入する() {
		VendingMachine vm = new VendingMachine();
		vm.put(1000);
		Juice j = vm.buy("水");
		assertThat(j.getName(), is("水"));
		int total = vm.getTotal();
		assertThat(total, is(900));
		int stock = vm.getJuiceStock("水");
		assertThat(stock, is(4));
		stock = vm.getJuiceStock("レッドブル");
		assertThat(stock, is(5));

		j = vm.buy("レッドブル");
		assertThat(j.getName(), is("レッドブル"));
		total = vm.getTotal();
		assertThat(total, is(700));

		j = vm.buy("コーラ");
		assertThat(j.getName(), is("コーラ"));
		total = vm.getTotal();
		assertThat(total, is(580));

		int sales = vm.getSales();
		assertThat(sales, is(420));
	}

このテストで、レッドブルの在庫数を正しく返せてないことがわかる。
getJuiceStocck() をきちんと実装しなおす。

	public int getJuiceStock(String name) {
		juices = map.get(name);
		return juices.size();
	}

購入可能なドリンクのリストを知りたい!
テストを作成する。

	@Test
	void 購入可能なドリンクのリスト() {
		VendingMachine vm = new VendingMachine();
		Juice[] list = vm.getBuyableJuices();
		assertThat(list.length, is(0));
	}

コンパイルエラーを解消する。
VendingMachine に以下のメソッドを追加する。

	public Juice[] getBuyableJuices() {
		return null;
	}

テストには失敗するので、テストにパスするように実装する。
とりあえず fake で。

	public Juice[] getBuyableJuices() {
		return new Juice[0];
	}

テストを追加する。
100円を投入すると水を購入できる。

	@Test
	void 購入可能なドリンクのリスト() {
		VendingMachine vm = new VendingMachine();
		Juice[] list = vm.getBuyableJuices();
		assertThat(list.length, is(0));
		vm.put(100);
		list = vm.getBuyableJuices();
		assertThat(list.length, is(1));
		assertThat(list[0].getName(), is("水"));
	}

100円を追加投入すると3種類のドリンクを購入できる。

	@Test
	void 購入可能なドリンクのリスト() {
		VendingMachine vm = new VendingMachine();
		Juice[] list = vm.getBuyableJuices();
		assertThat(list.length, is(0));
		vm.put(100);
		list = vm.getBuyableJuices();
		assertThat(list.length, is(1));
		assertThat(list[0].getName(), is("水"));
		vm.put(100);
		list = vm.getBuyableJuices();
		assertThat(list.length, is(3));
	}

手抜きの実装でテストをパスさせる。

	public Juice[] getBuyableJuices() {
		if (total >= 200) {
			Juice[] list = {
					new Juice("水", 100),
					new Juice("コーラ", 120),
					new Juice("レッドブル", 200)
				};
			return list;
		}
		if (total >= 120) {
			Juice[] list = {
					new Juice("水", 100),
					new Juice("コーラ", 120),
				};
			return list;

		}
		if (total >= 100) {
			Juice[] list = {
					new Juice("水", 100),
				};
			return list;

		}
		return new Juice[0];
	}

在庫がなくなったらリストに出ないテストを作成する。
合計700円を投入して水を5個買うと、200円残る。
水の在庫がなくなったので、リストはコーラとレッドブルの2個だけになる。

	@Test
	void 購入可能なドリンクのリスト() {
		VendingMachine vm = new VendingMachine();
		Juice[] list = vm.getBuyableJuices();
		assertThat(list.length, is(0));
		vm.put(100);
		list = vm.getBuyableJuices();
		assertThat(list.length, is(1));
		assertThat(list[0].getName(), is("水"));
		vm.put(100);
		list = vm.getBuyableJuices();
		assertThat(list.length, is(3));
		vm.put(500);
		for (int i = 0; i < 5; i++) {
			Juice j = vm.buy("水");
			assertThat(j.getName(), is("水"));
		}
		list = vm.getBuyableJuices();
		assertThat(list.length, is(2));
	}
	public Juice[] getBuyableJuices() {
		Collection<List<Juice>> c = map.values();
		List<Juice> list = new ArrayList<>();
		for (List<Juice> l : c) {
			if (l.size() == 0) continue;
			Juice j = l.get(0);
			if (j.getPrice() > total) continue;
			list.add(j);
		}
		return list.toArray(new Juice[0]);
	}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください