「釣り銭がないときは購入できないようにする」テストに対して、VendingMachine側の実装を作っていく。
まず釣り銭を出せるかどうかをチェックするメソッドを用意する。
それをcanBuy()で呼び出すようにする。
public boolean canBuy(String name) {
List<Juice> list = juices.get(name);
if (list.size() == 0) return false;
Juice j = list.get(0);
if (total < j.getPrice()) return false;
// 釣り銭を考慮する
int r = total - j.getPrice();
// 釣り銭を用意できるか?
if (!isRefundable(r)) return false;
return true;
}
private boolean isRefundable(int r) {
int y500 = y500coins;
int y100 = y100coins;
int y50 = y50coins;
int y10 = y10coins;
while (r >= 500 && y500 > 0) {
y500--;
r -= 500;
}
while (r >= 100 && y100 > 0) {
y100--;
r -= 100;
}
while (r >= 50 && y50 > 0) {
y50--;
r -= 50;
}
while (r >= 10 && y10 > 0) {
y10--;
r -= 10;
}
if (r > 0) return false;
return true;
}
全体の動作をわかりやすくするために、メッセージ出力を追加してみる。
package jp.abc;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 自動販売機クラス
* @author satoshis
*
*/
public class VendingMachine {
private int total = 0;
private Map<String, List<Juice>> juices = new HashMap<>();
private List<Juice> colas = new ArrayList<>();
private List<Juice> waters = new ArrayList<>();
private List<Juice> redbulls = new ArrayList<>();
private int y500coins = 10;
private int y100coins = 10;
private int y50coins = 10;
private int y10coins = 10;
public VendingMachine() {
for (int i = 0; i < 5; i++) {
colas.add(new Juice("コーラ", 120));
waters.add(new Juice("水", 100));
redbulls.add(new Juice("レッドブル", 200));
}
juices.put("コーラ", colas);
juices.put("水", waters);
juices.put("レッドブル", redbulls);
}
/**
* 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;
if (money == 10) y10coins++;
if (money == 50) y50coins++;
if (money == 100) y100coins++;
if (money == 500) y500coins++;
}
}
public int entered() {
return total;
}
public int refund() {
int r = total;
while (total > 0) {
while (total >= 500 && y500coins > 0) {
y500coins--;
total -= 500;
}
while (total >= 100 && y100coins > 0) {
y100coins--;
System.out.println("100円玉残り:" + y100coins);
total -= 100;
}
while (total >= 50 && y50coins > 0) {
y50coins--;
System.out.println("50円玉残り:" + y50coins);
total -= 50;
}
while (total >= 10 && y10coins > 0) {
y10coins--;
System.out.println("10円玉残り:" + y10coins);
total -= 10;
}
}
return r;
}
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;
}
public boolean isStock(String name) {
return true;
}
public boolean canBuy(String name) {
List<Juice> list = juices.get(name);
// 在庫がなければfalse
if (list.size() == 0) return false;
Juice j = list.get(0);
// 金額が足りないならfalse
if (total < j.getPrice()) return false;
// 釣り銭を考慮する
int r = total - j.getPrice();
// 釣り銭を用意できるか?
if (!isRefundable(r)) return false;
return true;
}
private boolean isRefundable(int r) {
System.out.println(r);
int y500 = y500coins;
int y100 = y100coins;
int y50 = y50coins;
int y10 = y10coins;
while (r >= 500 && y500 > 0) {
y500--;
r -= 500;
}
while (r >= 100 && y100 > 0) {
y100--;
System.out.println("y100:" + y100);
r -= 100;
}
while (r >= 50 && y50 > 0) {
y50--;
System.out.println("y50:" + y50);
r -= 50;
}
while (r >= 10 && y10 > 0) {
y10--;
System.out.println("y10:" + y10);
r -= 10;
}
if (r > 0) {
System.out.println(r);
return false;
}
return true;
}
public Juice buy(String name) {
List<Juice> list = juices.get(name);
Juice j = list.remove(0);
total -= j.getPrice();
return j;
}
public Juice getJuice(String name) {
List<Juice> list = juices.get(name);
return list.get(0);
}
}
VendingMachineTest
@Test
void 釣り銭がないときは購入できないようにする() {
VendingMachine vm = new VendingMachine();
// 1本目の水を購入
System.out.println("1本目の水を購入");
vm.put(500);
boolean b = vm.canBuy("水");
assertEquals(true, b);
Juice j = vm.buy("水");
assertEquals("水", j.getName());
int m = vm.refund();
assertEquals(400, m);
// 100円玉残り6個
// 2本目の水を購入
System.out.println("2本目の水を購入");
vm.put(500);
b = vm.canBuy("水");
vm.buy("水");
m = vm.refund();
assertEquals(400, m);
// 100円玉残り2個
// 3本目の水を購入
System.out.println("3本目の水を購入");
vm.put(500);
b = vm.canBuy("水");
vm.buy("水");
m = vm.refund();
assertEquals(400, m);
// 100円玉残り0個、50円玉残り6個、10円玉残り10個
// 4本目の水を購入
System.out.println("4本目の水を購入");
vm.put(500);
b = vm.canBuy("水");
vm.buy("水");
m = vm.refund();
assertEquals(400, m);
// 100円玉残り0個、50円玉残り0個、10円玉残り0個
// 5本目の水を購入?
System.out.println("5本目の水を購入");
vm.put(500);
b = vm.canBuy("水");
assertEquals(false, b);
}
釣り銭がないときの動作を確認するためのテストを追加する。
@Test
void 釣り銭がないときは購入できないようにする() {
VendingMachine vm = new VendingMachine();
// 1本目の水を購入
System.out.println("1本目の水を購入");
vm.put(500);
boolean b = vm.canBuy("水");
assertEquals(true, b);
Juice j = vm.buy("水");
assertEquals("水", j.getName());
int m = vm.refund();
assertEquals(400, m);
// 100円玉残り6個
// 2本目の水を購入
System.out.println("2本目の水を購入");
vm.put(500);
b = vm.canBuy("水");
vm.buy("水");
m = vm.refund();
assertEquals(400, m);
// 100円玉残り2個
// 3本目の水を購入
System.out.println("3本目の水を購入");
vm.put(500);
b = vm.canBuy("水");
vm.buy("水");
m = vm.refund();
assertEquals(400, m);
// 100円玉残り0個、50円玉残り6個、10円玉残り10個
// 4本目の水を購入
System.out.println("4本目の水を購入");
vm.put(500);
b = vm.canBuy("水");
vm.buy("水");
m = vm.refund();
assertEquals(400, m);
// 100円玉残り0個、50円玉残り0個、10円玉残り0個
// 5本目の水を購入?
System.out.println("5本目の水を購入");
vm.put(500);
b = vm.canBuy("水");
assertEquals(false, b);
m = vm.refund();
assertEquals(500, m);
// 100円だけ入れて水を買ってみる
vm.put(100);
b = vm.canBuy("水");
assertEquals(true, b);
vm.buy("水");
m = vm.refund();
assertEquals(0, m);
// コーラを買ってみる
vm.put(100);
vm.put(100);
b = vm.canBuy("コーラ");
assertEquals(false, b);
vm.put(10);
vm.put(10);
b = vm.canBuy("コーラ");
assertEquals(true, b);
vm.buy("コーラ");
m = vm.refund();
assertEquals(100, m);
}
TDDはここまでで終わり。
次はWebアプリケーションを作っていく。
SpringBootプロジェクト
新しいプロジェクトを作成する。
[ファイル]-[新規]-[プロジェクト]を選択する。
新規プロジェクトのウィザードで「Spring スターター・プロジェクト」を選択して「次へ」
プロジェクト名が「demo」になっているので、そのままで「次へ」
「新規Springスターター・プロジェクト依存関係」で「Web」の下の「Spring Web」を選択して「完了」
パッケージエクスプローラーに「demo」プロジェクトが作られる。
demoプロジェクトは、Mavenというビルドツールを使うように設定してある。
最初にプロジェクト名[demo]を右クリックして[Maven]-[プロジェクトの更新]を選択する。
次にプロジェクト名[demo]を右クリックして[実行]-[Maven install]を選択する。
最後に「BUILD SUCCESS」と表示されればOK。
Webアプリケーションを起動するには「demo」を右クリックして[実行]-[Spring Boot アプリケーション]を選択する。
コンソールに「Started DemoApplication」と表示されれば起動されている。
プラウザで http://localhost:8080/ にアクセスすると「Whitelabel Error Page」と表示される。→Webアプリケーションが起動している。
コンソールタブの赤い■をクリックしてWebアプリケーションを終了する。
Hello worldを作ってみる。
src/main/java を右クリックして[新規]-[クラス]を選択する。
クラス名に「HelloController」を入力して「完了」する。
以下のコードを入力し、「demo」を右クリックして[実行]-[Spring Boot アプリケーション]を選択する。
コンソールに「Started DemoApplication」と表示されれば起動されている。
package com.example.demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String index() {
return "Hello world!";
}
}
http://localhost:8080/ にアクセスすると「Hello world」と表示する。
HTMLを表示するために、thymeleafを追加する。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
src/main/java を右クリックして[新規]-[クラス]を選択する。
クラス名に「IndexController」を入力して「完了」する。
以下のコードを入力する。
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping("/")
public String index() {
return "index";
}
}
src/main/resouces の中にある templates を右クリックして[新規]-[その他]を選択。
「HTMLファイル」を選択して「次へ」をクリック。
ファイル名を「index.html」にして「完了」する。
以下のコードを入力して、「demo」を右クリックして[実行]-[Spring Boot アプリケーション]を選択してWebアプリケーションを起動する。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>index.html</title> </head> <body> <h1>Hello spring boot</h1> </body> </html>
ブラウザで「http://localhost:8080/」にアクセスして「Hello spring boot」と表示されればOK。