Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その46 )( 貸出承認画面の作成6 )
概要
Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その45 )( 貸出承認画面の作成5 ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- 貸出承認画面の作成
- テストの作成 ( 2回に分けて書きます )
- 貸出承認画面の作成
参照したサイト・書籍
Getting started with Hibernate Validator
http://hibernate.org/validator/documentation/getting-started/- カスタム Bean Validation のテストで、テストメソッド内で Bean Validation を実行する方法を調査した時に参照しました。
com.google.common.base - Class Strings
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Strings.html- Guava の Strings クラスのドキュメントです。
- "X" を繰り返して生成された 128 文字の文字列を生成する方法を調査した時に参照しました。
目次
- テスト作成対象のクラスを決める
- printClassWhatNotMakeTest タスクのチェック対象外のパッケージを設定する
- ValuesEnumValidator クラスのテストの作成
- ValuesHelper クラスの変更
- Mail003Helper クラスのテストの作成
- LendingapprovalFormValidator クラスのテストの作成
手順
テスト作成対象のクラスを決める
Gradle projects View から printClassWhatNotMakeTest タスクを実行します。
出力されたクラスに対して以下の対応を行います。
- 以下のアノテーションは printClassWhatNotMakeTest タスクのチェック対象外にします。
- 今回は Spock ではテストを作成しません。
- 以下のクラスは JUnit でテストを作成します。
- src/main/java/ksbysample/webapp/lending/values/validation/ValuesEnumValidator.java
- src/main/java/ksbysample/webapp/lending/helper/mail/Mail003Helper.java
- src/main/java/ksbysample/webapp/lending/web/lendingapproval/LendingapprovalFormValidator.java
- src/main/java/ksbysample/webapp/lending/web/lendingapproval/LendingapprovalController.java
printClassWhatNotMakeTest タスクのチェック対象外のパッケージを設定する
- build.gradle を リンク先の内容 に変更します。
ValuesEnumValidator クラスのテストの作成
src/main/java/ksbysample/webapp/lending/values/validation の下の ValuesEnumValidator.java で「Create Test」ダイアログを表示し、テストクラスを作成します。
src/test/java/ksbysample/webapp/lending/values/validation の下に ValuesEnumValidatorTest.java が作成されますので、リンク先の内容 に変更します。
テストを実行します。ValuesEnumValidatorTest クラスのクラス名の左側に表示されているアイコンをクリックしてコンテキストメニューを表示後「Run 'ValuesEnumValidatorTest' with Coverage」を選択します。
テストが成功することが確認できます。
※Spock で作りたかったのですが、Spock のテストクラス内で lombok のアノテーションを付加した Values 列挙型を定義できなかったので、JUnit4 で作成しました。Groovy だと lombok のアノテーションが効かないようです。
ValuesHelper クラスの変更
Mail003Helper クラスのテストを作成する前に ValuesHelper クラスを変更します。Mail003Helper クラスを実装した時に以下のように実装したのですが、さすがに <?>
はないかな。。。と思ったので、書かなくてすむように変更します。
@Autowired private ValuesHelper<?> vh;
またインナークラスの Mail003BookData のコンストラクタ内で以下のように実装したのですが、Java のソース内ならば第1引数は "LendingBookApprovalResultValues"
ではなく LendingBookApprovalResultValues.class
と書けた方がよいと思ったので、書けるようにメソッドを追加します。
this.approvalResultStr = vh.getText("LendingBookApprovalResultValues", lendingBook.getApprovalResult());
src/main/java/ksbysample/webapp/lending/values の下の ValuesHelper.java を リンク先の内容 に変更します。
src/main/java/ksbysample/webapp/lending/helper/mail の下の Mail003Helper.java を リンク先の内容 に変更します。
Mail003Helper クラスのテストの作成
src/main/java/ksbysample/webapp/lending/helper/mail の下の Mail003Helper.java で「Create Test」ダイアログを表示し、テストクラスを作成します。
src/test/java/ksbysample/webapp/lending/helper/mail の下に Mail003HelperTest.java が作成されますので、リンク先の内容 に変更します。
src/test/resources/ksbysample/webapp/lending/helper/mail/assertdata/003 の下に message.txt を作成します。作成後、リンク先の内容 に変更します。
テストを実行します。Mail003HelperTest クラスのクラス名の左側に表示されているアイコンをクリックしてコンテキストメニューを表示後「Run 'Mail003HelperTest' with Coverage」を選択します。
テストが成功することが確認できます。
LendingapprovalFormValidator クラスのテストの作成
テストデータを作成します。src/test/resources/ksbysample/webapp/lending/web の下に lendingapproval ディレクトリを作成します。
src/test/resources/ksbysample/webapp/lending/web/lendingapproval の下に LendingapprovalForm_001.yaml, LendingapprovalForm_002.yaml, LendingapprovalForm_003.yaml, LendingapprovalForm_004.yaml, LendingapprovalForm_005.yaml を作成し、リンク先の内容 に変更します。
テストデータの YAML ファイルを読み込む時に問題があることが判明したため、メソッド名を変更します。src/main/java/ksbysample/webapp/lending/web/lendingapproval の下の LendingapprovalForm.java を リンク先の内容 に変更します。
src/main/java/ksbysample/webapp/lending/web/lendingapproval の下の LendingapprovalFormValidator.java で「Create Test」ダイアログを表示し、テストクラスを作成します。
src/test/java/ksbysample/webapp/lending/web/lendingapproval の下に LendingapprovalFormValidatorTest.java が作成されますので、リンク先の内容 に変更します。
テストを実行します。LendingapprovalFormValidatorTest クラスのクラス名の左側に表示されているアイコンをクリックしてコンテキストメニューを表示後「Run 'LendingapprovalFormValidatorTe...' with Coverage」を選択します。
テストが成功することが確認できます。
ソースコード
build.gradle
task printClassWhatNotMakeTest << { def srcDir = new File("src/main/java"); def excludePaths = [ "src/main/java/ksbysample/webapp/lending/Application.java" , "src/main/java/ksbysample/webapp/lending/config" , "src/main/java/ksbysample/webapp/lending/cookie" , "src/main/java/ksbysample/webapp/lending/dao" , "src/main/java/ksbysample/webapp/lending/entity" , "src/main/java/ksbysample/webapp/lending/exception" , "src/main/java/ksbysample/webapp/lending/helper/page/PagenationHelper.java" , "src/main/java/ksbysample/webapp/lending/security/LendingUser.java" , "src/main/java/ksbysample/webapp/lending/security/RoleAwareAuthenticationSuccessHandler.java" , "src/main/java/ksbysample/webapp/lending/service/calilapi/response" , "src/main/java/ksbysample/webapp/lending/service/file/BooklistCSVRecord.java" , "src/main/java/ksbysample/webapp/lending/service/openweathermapapi" , "src/main/java/ksbysample/webapp/lending/service/queue/InquiringStatusOfBookQueueMessage.java" , "src/main/java/ksbysample/webapp/lending/util/doma" , "src/main/java/ksbysample/webapp/lending/util/velocity/VelocityUtils.java" , "src/main/java/ksbysample/webapp/lending/values/validation/ValuesEnum.java" , "src/main/java/ksbysample/webapp/lending/web/.+/.+Service.java" , "src/main/java/ksbysample/webapp/lending/webapi/common/CommonWebApiResponse.java" , "src/main/java/ksbysample/webapp/lending/webapi/weather" ]; def excludeFileNamePatterns = [ ".*EventListener.java" , ".*Dto.java" , ".*Form.java" , ".*Values.java" ]; compareSrcAndTestDir(srcDir, excludePaths, excludeFileNamePatterns); }
- excludePaths に
, "src/main/java/ksbysample/webapp/lending/values/validation/ValuesEnum.java"
を追加します。
ValuesEnumValidatorTest.java
package ksbysample.webapp.lending.values.validation; import ksbysample.webapp.lending.Application; import ksbysample.webapp.lending.values.Values; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration public class ValuesEnumValidatorTest { // テスト用 Value 列挙型 @Getter @AllArgsConstructor private enum TestValues implements Values { FIRST("1", "1番目") , SECOND("2", "2番目") , THIRD("3", "3番目"); private final String value; private final String text; } // テスト用 POJO クラス @Data private class NotAllowEmptyTestClass { @ValuesEnum(enumClass = TestValues.class) private String testStr; } // テスト用 POJO クラス @Data private class AllowEmptyTestClass { @ValuesEnum(enumClass = TestValues.class, allowEmpty = true) private String testStr; } private Validator validator; @Before public void setup() { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); validator = factory.getValidator(); } @Test public void ValuesEnumBeanValidationTest_AllowEmpty_False() { NotAllowEmptyTestClass notAllowEmptyTestClass = new NotAllowEmptyTestClass(); // null の場合にはエラーにはエラーは発生しない ( チェックが実行されない ) notAllowEmptyTestClass.setTestStr(null); Set<ConstraintViolation<NotAllowEmptyTestClass>> constraintViolations = validator.validate(notAllowEmptyTestClass); assertThat(constraintViolations).hasSize(0); // Value に定義されている値の場合にはエラーは発生しない notAllowEmptyTestClass.setTestStr("1"); constraintViolations = validator.validate(notAllowEmptyTestClass); assertThat(constraintViolations).hasSize(0); // Value に定義されていない値の場合にはエラーが発生する notAllowEmptyTestClass.setTestStr("4"); constraintViolations = validator.validate(notAllowEmptyTestClass); assertThat(constraintViolations).hasSize(1); // Value に定義されている値が含まれていてもエラーが発生する notAllowEmptyTestClass.setTestStr("2test"); constraintViolations = validator.validate(notAllowEmptyTestClass); assertThat(constraintViolations).hasSize(1); // Text に定義されている値の場合にはエラーが発生する notAllowEmptyTestClass.setTestStr("3番目"); constraintViolations = validator.validate(notAllowEmptyTestClass); assertThat(constraintViolations).hasSize(1); // 空文字列の場合にはエラーが発生する notAllowEmptyTestClass.setTestStr(""); constraintViolations = validator.validate(notAllowEmptyTestClass); assertThat(constraintViolations).hasSize(1); } @Test public void ValuesEnumBeanValidationTest_AllowEmpty_True() { AllowEmptyTestClass allowEmptyTestClass = new AllowEmptyTestClass(); // null の場合にはエラーにはエラーは発生しない ( チェックが実行されない ) allowEmptyTestClass.setTestStr(null); Set<ConstraintViolation<AllowEmptyTestClass>> constraintViolations = validator.validate(allowEmptyTestClass); assertThat(constraintViolations).hasSize(0); // Value に定義されている値の場合にはエラーは発生しない allowEmptyTestClass.setTestStr("1"); constraintViolations = validator.validate(allowEmptyTestClass); assertThat(constraintViolations).hasSize(0); // Value に定義されていない値の場合にはエラーが発生する allowEmptyTestClass.setTestStr("4"); constraintViolations = validator.validate(allowEmptyTestClass); assertThat(constraintViolations).hasSize(1); // Value に定義されている値が含まれていてもエラーが発生する allowEmptyTestClass.setTestStr("2test"); constraintViolations = validator.validate(allowEmptyTestClass); assertThat(constraintViolations).hasSize(1); // Text に定義されている値の場合にはエラーが発生する allowEmptyTestClass.setTestStr("3番目"); constraintViolations = validator.validate(allowEmptyTestClass); assertThat(constraintViolations).hasSize(1); // 空文字列の場合にはエラーは発生しない allowEmptyTestClass.setTestStr(""); constraintViolations = validator.validate(allowEmptyTestClass); assertThat(constraintViolations).hasSize(0); } }
- クラス内にテスト用の Values 列挙型、POJO クラスを作成し、それらを使用してテストします。
ValuesHelper.java
package ksbysample.webapp.lending.values; import com.google.common.reflect.ClassPath; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.Map; import java.util.stream.Collectors; @Component("vh") public class ValuesHelper { private final Map<String, String> valuesObjList; private ValuesHelper() throws IOException { ClassLoader loader = Thread.currentThread().getContextClassLoader(); valuesObjList = ClassPath.from(loader).getTopLevelClasses(this.getClass().getPackage().getName()) .stream() .filter(classInfo -> !classInfo.getName().equals(this.getClass().getName())) .collect(Collectors.toMap(ClassPath.ClassInfo::getSimpleName, ClassPath.ClassInfo::getName)); } @SuppressWarnings("unchecked") public <T extends Enum<T> & Values> String getValue(String classSimpleName, String valueName) throws ClassNotFoundException { Class<T> enumType = (Class<T>) Class.forName(this.valuesObjList.get(classSimpleName)); T val = Enum.valueOf(enumType, valueName); return val.getValue(); } public <T extends Enum<T> & Values> String getValue(Class<T> enumType, String valueName) { T val = Enum.valueOf(enumType, valueName); return val.getValue(); } @SuppressWarnings("unchecked") public <T extends Enum<T> & Values> String getText(String classSimpleName, String value) throws ClassNotFoundException { Class<T> enumType = (Class<T>) Class.forName(this.valuesObjList.get(classSimpleName)); String result = ""; for (T val : enumType.getEnumConstants()) { if (val.getValue().equals(value)) { result = val.getText(); break; } } return result; } public <T extends Enum<T> & Values> String getText(Class<T> enumType, String value) { String result = ""; for (T val : enumType.getEnumConstants()) { if (val.getValue().equals(value)) { result = val.getText(); break; } } return result; } @SuppressWarnings("unchecked") public <T extends Enum<T> & Values> T[] values(String classSimpleName) throws ClassNotFoundException { Class<T> enumType = (Class<T>) Class.forName(this.valuesObjList.get(classSimpleName)); return enumType.getEnumConstants(); } }
- クラス名の ValuesHelper の後に記述していた
<T extends Enum<T> & Values>
を各メソッドのアクセス修飾子の後に書くように修正します。 - 以下の2つのメソッドを追加します。
String getValue(Class<T> enumType, String valueName)
String getText(Class<T> enumType, String value)
Mail003Helper.java
package ksbysample.webapp.lending.helper.mail; import ksbysample.webapp.lending.entity.LendingBook; import ksbysample.webapp.lending.util.velocity.VelocityUtils; import ksbysample.webapp.lending.values.LendingBookApprovalResultValues; import ksbysample.webapp.lending.values.ValuesHelper; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Component; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Component public class Mail003Helper { private final String TEMPLATE_LOCATION_TEXTMAIL = "mail/mail003-body.vm"; private final String FROM_ADDR = "lendingapp@sample.com"; private final String SUBJECT = "貸出申請が承認・却下されました"; @Autowired private VelocityUtils velocityUtils; @Autowired private JavaMailSender mailSender; @Autowired private ValuesHelper vh; public MimeMessage createMessage(String toAddr, Long lendingAppId, List<LendingBook> lendingBookList) throws MessagingException { List<Mail003BookData> mail003BookDataList = lendingBookList.stream() .map(Mail003BookData::new) .collect(Collectors.toList()); MimeMessage mimeMessage = this.mailSender.createMimeMessage(); MimeMessageHelper message = new MimeMessageHelper(mimeMessage, false, "UTF-8"); message.setFrom(FROM_ADDR); message.setTo(toAddr); message.setSubject(SUBJECT); message.setText(generateTextUsingVelocity(lendingAppId, mail003BookDataList), false); return message.getMimeMessage(); } private String generateTextUsingVelocity(Long lendingAppId, List<Mail003BookData> mail003BookDataList) { Map<String, Object> model = new HashMap<>(); model.put("lendingAppId", lendingAppId); model.put("mail003BookDataList", mail003BookDataList); return velocityUtils.merge(this.TEMPLATE_LOCATION_TEXTMAIL, model); } @Data public class Mail003BookData { private String approvalResultStr; private String bookName; public Mail003BookData(LendingBook lendingBook) { this.approvalResultStr = vh.getText(LendingBookApprovalResultValues.class, lendingBook.getApprovalResult()); this.bookName = lendingBook.getBookName(); } } }
private ValuesHelper<?> vh;
→private ValuesHelper vh;
へ変更します。- インナークラスの Mail003BookData のコンストラクタ
public Mail003BookData(LendingBook lendingBook)
の以下の点を変更します。vh.getText(LendingBookApprovalResultValues.class, ...);
→vh.getText(LendingBookApprovalResultValues.class, ...);
へ変更します。- メインの処理の前後に書いている
try { ... } catch (ClassNotFoundException e) { throw new RuntimeException(e); }
を削除します。
Mail003HelperTest.java
package ksbysample.webapp.lending.helper.mail; import com.google.common.base.Charsets; import com.google.common.base.Strings; import ksbysample.webapp.lending.Application; import ksbysample.webapp.lending.entity.LendingBook; import ksbysample.webapp.lending.values.ValuesHelper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import javax.mail.Message; import javax.mail.internet.MimeMessage; import java.io.File; import java.util.ArrayList; import java.util.List; import static ksbysample.webapp.lending.values.LendingBookApprovalResultValues.APPROVAL; import static ksbysample.webapp.lending.values.LendingBookApprovalResultValues.REJECT; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration public class Mail003HelperTest { @Autowired private Mail003Helper mail003Helper; @Autowired private ValuesHelper vh; @Test public void testCreateMessage() throws Exception { List<LendingBook> lendingBookList = new ArrayList<>(); // 1件目 LendingBook lendingBook = new LendingBook(); lendingBook.setBookName("x"); lendingBook.setApprovalResult(APPROVAL.getValue()); lendingBookList.add(lendingBook); // 2件目 lendingBook = new LendingBook(); lendingBook.setBookName(Strings.repeat("X", 128)); lendingBook.setApprovalResult(REJECT.getValue()); lendingBookList.add(lendingBook); MimeMessage message = mail003Helper.createMessage("test@sample.com", 1L, lendingBookList); assertThat(message.getRecipients(Message.RecipientType.TO)) .extracting(Object::toString) .containsOnly("test@sample.com"); assertThat(message.getContent()) .isEqualTo(com.google.common.io.Files.toString( new File("src/test/resources/ksbysample/webapp/lending/helper/mail/assertdata/003/message.txt") , Charsets.UTF_8)); } }
helper/mail/assertdata/003/message.txt
貸出申請が承認・却下されました。 ======================================================================== 承認/却下 書籍 ------------------------------------------------------------------------ 承認 x 却下 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ======================================================================== 詳細は以下のURLから確認してください。 http://localhost:8080/confirmresult?lendingAppId=1
LendingapprovalForm_001.yaml, LendingapprovalForm_002.yaml, LendingapprovalForm_003.yaml, LendingapprovalForm_004.yaml, LendingapprovalForm_005.yaml
■LendingapprovalForm_001.yaml
!!ksbysample.webapp.lending.web.lendingapproval.LendingapprovalForm # 「確定」ボタンが押された場合 # 3件全て「承認」も「却下」も選択していない lendingApp: lendingAppId: 105 status: 3 lendingUserId: 1 approvalUserId: version: 1 username: temporarySave applyingBookFormList: - lendingBookId: 522 isbn: 978-4-7741-6366-6 bookName: GitHub実践入門 lendingAppReason: 開発で使用する為 approvalResult: approvalReason: version: 1 - lendingBookId: 524 isbn: 978-4-7741-5377-3 bookName: JUnit実践入門 lendingAppReason: 勉強の為 approvalResult: approvalReason: version: 1 - lendingBookId: 525 isbn: 978-4-7973-8014-9 bookName: Java最強リファレンス lendingAppReason: 勉強会の調査の為 approvalResult: approvalReason: version: 1
■LendingapprovalForm_002.yaml
!!ksbysample.webapp.lending.web.lendingapproval.LendingapprovalForm # 「確定」ボタンが押された場合 # 3件全て「却下」が選択されているが却下理由が入力されていない lendingApp: lendingAppId: 105 status: 3 lendingUserId: 1 approvalUserId: version: 1 username: temporarySave applyingBookFormList: - lendingBookId: 522 isbn: 978-4-7741-6366-6 bookName: GitHub実践入門 lendingAppReason: 開発で使用する為 approvalResult: 2 approvalReason: version: 1 - lendingBookId: 524 isbn: 978-4-7741-5377-3 bookName: JUnit実践入門 lendingAppReason: 勉強の為 approvalResult: 2 approvalReason: version: 1 - lendingBookId: 525 isbn: 978-4-7973-8014-9 bookName: Java最強リファレンス lendingAppReason: 勉強会の調査の為 approvalResult: 2 approvalReason: version: 1
■LendingapprovalForm_003.yaml
!!ksbysample.webapp.lending.web.lendingapproval.LendingapprovalForm # 「確定」ボタンが押された場合 # 2件目は「承認」も「却下」も選択されていない、3件目は「却下」が選択されているが却下理由が入力されていない lendingApp: lendingAppId: 105 status: 3 lendingUserId: 1 approvalUserId: version: 1 username: temporarySave applyingBookFormList: - lendingBookId: 522 isbn: 978-4-7741-6366-6 bookName: GitHub実践入門 lendingAppReason: 開発で使用する為 approvalResult: 1 approvalReason: version: 1 - lendingBookId: 524 isbn: 978-4-7741-5377-3 bookName: JUnit実践入門 lendingAppReason: 勉強の為 approvalResult: approvalReason: version: 1 - lendingBookId: 525 isbn: 978-4-7973-8014-9 bookName: Java最強リファレンス lendingAppReason: 勉強会の調査の為 approvalResult: 2 approvalReason: version: 1
■LendingapprovalForm_004.yaml
!!ksbysample.webapp.lending.web.lendingapproval.LendingapprovalForm # 「確定」ボタンが押された場合 # 3件全て「承認」が選択されている lendingApp: lendingAppId: 105 status: 3 lendingUserId: 1 approvalUserId: version: 1 username: temporarySave applyingBookFormList: - lendingBookId: 522 isbn: 978-4-7741-6366-6 bookName: GitHub実践入門 lendingAppReason: 開発で使用する為 approvalResult: 1 approvalReason: version: 1 - lendingBookId: 524 isbn: 978-4-7741-5377-3 bookName: JUnit実践入門 lendingAppReason: 勉強の為 approvalResult: 1 approvalReason: version: 1 - lendingBookId: 525 isbn: 978-4-7973-8014-9 bookName: Java最強リファレンス lendingAppReason: 勉強会の調査の為 approvalResult: 1 approvalReason: version: 1
■LendingapprovalForm_005.yaml
!!ksbysample.webapp.lending.web.lendingapproval.LendingapprovalForm # 「確定」ボタンが押された場合 # 3件全て「却下」が選択されて、却下理由も入力されている lendingApp: lendingAppId: 105 status: 3 lendingUserId: 1 approvalUserId: version: 1 username: temporarySave applyingBookFormList: - lendingBookId: 522 isbn: 978-4-7741-6366-6 bookName: GitHub実践入門 lendingAppReason: 開発で使用する為 approvalResult: 2 approvalReason: 購入済です version: 1 - lendingBookId: 524 isbn: 978-4-7741-5377-3 bookName: JUnit実践入門 lendingAppReason: 勉強の為 approvalResult: 2 approvalReason: 自分で購入して勉強しましょう version: 1 - lendingBookId: 525 isbn: 978-4-7973-8014-9 bookName: Java最強リファレンス lendingAppReason: 勉強会の調査の為 approvalResult: 2 approvalReason: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX version: 1
LendingapprovalForm.java
package ksbysample.webapp.lending.web.lendingapproval; import ksbysample.webapp.lending.entity.LendingApp; import ksbysample.webapp.lending.entity.LendingBook; import lombok.Data; import lombok.NoArgsConstructor; import javax.validation.Valid; import java.util.List; import java.util.stream.Collectors; @Data @NoArgsConstructor public class LendingapprovalForm { private LendingApp lendingApp; private String username; @Valid private List<ApplyingBookForm> applyingBookFormList; public void setApplyingBookFormListFromLendingBookList(List<LendingBook> lendingBookList) { this.applyingBookFormList = null; if (lendingBookList != null) { this.applyingBookFormList = lendingBookList.stream() .map(ApplyingBookForm::new) .collect(Collectors.toList()); } } }
- メソッド名を
setApplyingBookFormList
→setApplyingBookFormListFromLendingBookList
へ変更します。IntelliJ IDEA のリファクタリング機能でリネームし、使用されている部分のリネームは IntelliJ IDEA に任せます。
LendingapprovalFormValidatorTest.java
package ksbysample.webapp.lending.web.lendingapproval; import ksbysample.webapp.lending.Application; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.validation.Errors; import org.springframework.validation.FieldError; import org.springframework.validation.MapBindingResult; import org.springframework.validation.ObjectError; import org.yaml.snakeyaml.Yaml; import java.util.HashMap; import static org.assertj.core.api.Assertions.assertThat; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration public class LendingapprovalFormValidatorTest { // テストデータ private LendingapprovalForm lendingapprovalForm_001 = (LendingapprovalForm) new Yaml().load(getClass().getResourceAsStream("LendingapprovalForm_001.yaml")); private LendingapprovalForm lendingapprovalForm_002 = (LendingapprovalForm) new Yaml().load(getClass().getResourceAsStream("LendingapprovalForm_002.yaml")); private LendingapprovalForm lendingapprovalForm_003 = (LendingapprovalForm) new Yaml().load(getClass().getResourceAsStream("LendingapprovalForm_003.yaml")); private LendingapprovalForm lendingapprovalForm_004 = (LendingapprovalForm) new Yaml().load(getClass().getResourceAsStream("LendingapprovalForm_004.yaml")); private LendingapprovalForm lendingapprovalForm_005 = (LendingapprovalForm) new Yaml().load(getClass().getResourceAsStream("LendingapprovalForm_005.yaml")); @Autowired private LendingapprovalFormValidator lendingapprovalFormValidator; @Test public void testValidate_全ての書籍で承認も却下も選択されていない場合はエラーになる() throws Exception { Errors errors = new MapBindingResult(new HashMap<String, String>(), ""); lendingapprovalFormValidator.validate(lendingapprovalForm_001, errors); assertThat(errors.hasGlobalErrors()).isTrue(); assertThat(errors.getGlobalErrorCount()).isEqualTo(1); assertThat(errors.getGlobalErrors()) .extracting(ObjectError::getCode) .containsOnly("LendingapprovalForm.applyingBookFormList.approvalResult.notAllCheckedErr"); assertThat(errors.hasFieldErrors()).isFalse(); } @Test public void testValidate_全ての書籍で却下が選択されいるが却下理由が入力されていない場合はエラーになる() throws Exception { Errors errors = new MapBindingResult(new HashMap<String, String>(), ""); lendingapprovalFormValidator.validate(lendingapprovalForm_002, errors); assertThat(errors.hasGlobalErrors()).isFalse(); assertThat(errors.hasFieldErrors()).isTrue(); assertThat(errors.getFieldErrorCount()).isEqualTo(3); assertThat(errors.getFieldErrors()) .extracting(FieldError::getField) .containsOnly("applyingBookFormList[0].approvalReason" , "applyingBookFormList[1].approvalReason" , "applyingBookFormList[2].approvalReason"); } @Test public void testValidate_一部の書籍は承認却下未選択で一部の書籍は却下理由未入力の場合はエラーになる() throws Exception { Errors errors = new MapBindingResult(new HashMap<String, String>(), ""); lendingapprovalFormValidator.validate(lendingapprovalForm_003, errors); assertThat(errors.hasGlobalErrors()).isTrue(); assertThat(errors.getGlobalErrorCount()).isEqualTo(1); assertThat(errors.getGlobalErrors()) .extracting(ObjectError::getCode) .containsOnly("LendingapprovalForm.applyingBookFormList.approvalResult.notAllCheckedErr"); assertThat(errors.hasFieldErrors()).isTrue(); assertThat(errors.getFieldErrorCount()).isEqualTo(1); assertThat(errors.getFieldErrors()) .extracting(FieldError::getField) .containsOnly("applyingBookFormList[2].approvalReason"); } @Test public void testValidate_全ての書籍で承認が選択されている場合はエラーにならない() throws Exception { Errors errors = new MapBindingResult(new HashMap<String, String>(), ""); lendingapprovalFormValidator.validate(lendingapprovalForm_004, errors); assertThat(errors.hasGlobalErrors()).isFalse(); assertThat(errors.hasFieldErrors()).isFalse(); } @Test public void testValidate_全ての書籍で却下が選択され却下理由も入力されている場合はエラーにならない() throws Exception { Errors errors = new MapBindingResult(new HashMap<String, String>(), ""); lendingapprovalFormValidator.validate(lendingapprovalForm_005, errors); assertThat(errors.hasGlobalErrors()).isFalse(); assertThat(errors.hasFieldErrors()).isFalse(); } }
履歴
2016/01/20
初版発行。