Más contenido relacionado La actualidad más candente (20) Similar a Spring bootでweb ユニットテスト編 (20) Spring bootでweb ユニットテスト編2. アジェンダ
はじめに
ユニットテストの必要性
ユニットテストの適用分野
ユニットテストをするためのプロダクト
Springでのユニットテスト
Resopitoryのユニットテスト
Serviceのユニットテスト
Controllerのユニットテスト(Validate)
Controllerのユニットテスト(画面遷移)
まとめ
17. if ( 処理(パターンAのデータ) != パターンAの正常結果 ) {
エラー
}
if ( 処理(パターンBのデータ) != パターンBの正常結果 ) {
エラー
}
ユニットテストの必要性
問題点1:過去の実績は現在においては不要の解決策
B:「そんなはずはないですよ。テストしましたから」(1ヶ月前に)
C:「あ、共通処理直しました」 (先週)
テストするためには
開発が終わっていないと
着手できない
テスト用のコードがあれば
いつでもテストが出来る
19. if ( 処理(パターンAのデータ) != パターンAの正常結果 ) {
エラー
}
if ( 処理(パターンBのデータ) != パターンBの正常結果 ) {
エラー
ユニットテストの必要性
問題点1:過去の実績は現在においては不要の解決策
B:「そんなはずはないですよ。テストしましたから」(1ヶ月前に)
C:「あ、共通処理直しました」 (先週)
理想的とは思えない汚コードの
修正は許されず、担当者が変
わるとメンテが不可能になる
余談・・・
結果が変わらないことが担保で
きているので、常に理想的で
きれいなコードを保てる
29. Resopitoryのユニットテスト
テスト用のクラスを準備をする
/** ProductRepositoryのUT */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = App.class)
public class ProductRepositoryTest {
/** 事前処理 */
@Before
public void 事前処理( ) throws Exception {
}
/** 事後処理 */
@After
public void 事後処理( ) throws Exception {
}
}
JUnitでSpringを動かすオマジナイ
Springを起動するクラスを記述
テストの事前処理
テストの事後処理
31. Resopitoryのユニットテスト
サンプルデータの準備
/** 事前処理 */
@Before
public void 事前処理() throws Exception {
Product product1 = new Product();
product1.productCode = 1;
product1.productName = "ガム";
product1.price = 100;
productRepository.save(product1);
Product product2 = new Product();
product2.productCode = 2;
product2.productName = "アメ";
product2.price = 120;
productRepository.save(product2);
}
テスト用データを
事前処理で用意する
(これ自体が保存のテストと
言えなくもない)
32. Resopitoryのユニットテスト
テストの実行
/** findOneメソッドのテスト */
@Test
public void findOneメソッドのテスト( ) {
Product product = productRepository.findOne(1);
assertEquals ( product.productName, "ガム“ );
}
テスト用メソッドだと宣言する
事前処理で用意した
データを取得する
評価メソッドで結果を評価する
product.productNameが
「ガム」ではない場合、
例外が発生しテスト失敗となる
※あくまでサンプルとして既定の処理を呼び出している。
本来は自身で作成した処理を呼んでテストする。
34. Serviceのユニットテスト
テスト用のクラスを準備をする
/** ProductServiceのUT */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = App.class)
public class ProductServiceTest {
/** 事前処理 */
@Before
public void 事前処理( ) throws Exception {
}
/** 事後処理 */
@After
public void 事後処理( ) throws Exception {
}
}
JUnitでSpringを動かすオマジナイ
Springを起動するクラスを記述
テストの事前処理
テストの事後処理
37. Serviceのユニットテスト
テストの実行
/** プロダクト一覧を取得できるかのテスト */
@Test
public void プロダクト一覧を取得できるかのテスト() {
List<Product> list = productService.getProductList();
}
テスト用メソッドだと宣言する
テスト対象の
ビジネスロジックを呼ぶ
評価メソッドで結果を評価する
(このサンプルでは未実装)
リストの件数や内容を評価する
コードを記述する
38. Controllerのユニットテスト(Validate)
テスト用のクラスを準備をする
/** ProductFormのUT */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = App.class)
public class ProductFormTest {
/** 事前処理 */
@Before
public void 事前処理( ) throws Exception {
}
/** 事後処理 */
@After
public void 事後処理( ) throws Exception {
}
}
JUnitでSpringを動かすオマジナイ
Springを起動するクラスを記述
テストの事前処理
テストの事後処理
42. Controllerのユニットテスト(Validate)
テストの実行
/** productNameの妥当性テスト */
@Test
public void productNameの妥当性テスト( ) throws Exception {
ProductForm productForm = new ProductForm( );
productForm.setProductCode( 1 );
productForm.setProductName( "ポテトチップスうすしお“ );
productForm.setPrice( 100 );
// バリデート
Set<ConstraintViolation<ProductForm>> violations =
validator.validate( productForm );
// 検証
assertEquals( violations.size( ), 1 );
for (ConstraintViolation<ProductForm> v: violations) {
assertTrue( v.getConstraintDescriptor( ).getAnnotation( )
instanceof Length);
テスト用メソッドだと宣言する
テスト対象の
フォームを初期化
productNameのみが
11文字でエラーになるはず
43. Controllerのユニットテスト(Validate)
テストの実行
ProductForm productForm = new ProductForm( );
productForm.setProductCode( 1 );
productForm.setProductName( "ポテトチップスうすしお“ );
productForm.setPrice( 100 );
// バリデート
Set<ConstraintViolation<ProductForm>> violations =
validator.validate( productForm );
// 検証
assertEquals( violations.size( ), 1 );
for (ConstraintViolation<ProductForm> v: violations) {
assertTrue( v.getConstraintDescriptor( ).getAnnotation( )
instanceof Length);
}
}
バリデートの実行
エラーの数は 1 つかチェック
エラーの種類が
Length かチェック
44. Controllerのユニットテスト(画面遷移)
テスト用のクラスを準備をする
/** ProductControllerのUT */
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringApplicationConfiguration(classes = App.class)
public class ProductControllerTest {
/** 事前処理 */
@Before
public void 事前処理( ) throws Exception {
}
/** 事後処理 */
@After
public void 事後処理( ) throws Exception {
}
}
JUnitでSpringを動かすオマジナイ
(Webアプリ用宣言を追加)
Springを起動するクラスを記述
テストの事前処理
テストの事後処理
48. Controllerのユニットテスト(画面遷移)
テストの実行(入力画面から確認画面に遷移)
/** 入力画面から確認画面に遷移するテスト */
@Test
public void 入力画面から確認画面に遷移するテスト() throws Exception {
ResultActions resultActions =
mockMvc.perform(post("/product/confirm")
.contentType(MediaType.APPLICATION_FORM
.param("productCode", "1")
.param("productName", "ガム")
.param("price", "100")
);
// レスポンスの検証
resultActions.andExpect(status().isOk())
.andExpect(model().hasNoErrors());
テスト用メソッドだと宣言する
URL「/public/confirm」に
POSTメソッドでアクセスする
入力画面で入力した値として
各種パラメータを付加する
50. まとめ
ユニットテストで単体テストを補完する
→ 画面を開いて境界値テスト等するより向いている
ユニットテストを過信しない
→ ユニットテストをすれば単体テストをしなくて良いわけではない
ユニットテストでテストのコストは下がらない
→ コードを書くので画面を開いてテストするよりコストはかかる
→ 時にはテストコードのテストも必要
テストをするのが目的で、テストを書くのが目的ではない
→ コーディングが楽しいからと言って、目的を失ってはいけない
→ テスト中毒は程々に
本体のコードを修正したらテストコードを直すのはマスト
→ テストが通らないテストコードはメンテナンスする意識を一気に失う
→ そのためテストコードのメンテナンスは怠らない(ビルドエラーは論外)
51. まとめ
参考
■Spring MVC 3.2のSpring MVC Testを触った - コンピュータクワガタ
http://kuwalab.hatenablog.jp/entry/20130402/p1
■ Spring3(というかJSR-303)でBeanValidationのテスト « ひよっこ。
https://prepro.wordpress.com/2011/01/15/spring3%E3%81%A8%E
3%81%84%E3%81%86%E3%81%8Bjsr-
303%E3%81%A7beanvalidation%E3%81%AE%E3%83%86%E3%82
%B9%E3%83%88/
■ JSR 303 Bean Validationで遊んでみるよ! - Yamkazu's Blog
http://yamkazu.hatenablog.com/entry/20110206/1296985545
■私のBeanValidationの使い方(Java EE Advent Calendar 2013) — 裏紙
http://backpaper0.github.io/2013/12/03/javaee_advent_calendar_2
013.html