Mockitoを利用すると、例外を発生させるMockプログラムも作成することができる。
今回は例外処理を含むプログラムをテストするJUnitのプログラムを作成してみたので、共有する。
前提条件
下記記事の「起動ポートの変更」までの手順が完了していること。
やってみたこと
テスト対象プログラムの作成
作成したサンプルプログラムの構成は以下の通り。
なお、上図の赤枠は、今回記載するサンプルプログラムの内容である。
テスト対象のコントローラクラスの内容は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import java.io.FileNotFoundException; @Controller public class DemoController { @Autowired private DemoComponent demoComponent; @RequestMapping("/") public String index(Model model){ String textString; try{ textString = demoComponent.getTextString(); }catch (Exception e){ String errMsg; if(e instanceof FileNotFoundException){ errMsg = "ファイルが見つかりませんでした"; }else{ errMsg = "入出力例外が発生しました"; } //エラー時はerror.htmlに遷移 model.addAttribute("errMsg", errMsg); return "error"; } //正常時はindex.htmlに遷移 model.addAttribute("textString", textString); return "index"; } } |
また、上記プログラムから呼び出されるコンポーネントクラスの内容は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.example.demo; import org.springframework.stereotype.Component; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; @Component public class DemoComponent { public String getTextString() throws IOException{ StringBuilder sb = new StringBuilder(); try(BufferedReader br = new BufferedReader( new FileReader("C:\\tmp\\test.txt"))) { String line; while ((line = br.readLine()) != null) { sb.append(line); } }catch (FileNotFoundException ex1){ throw ex1; }catch (IOException ex2){ throw ex2; } return sb.toString(); } } |
さらに、例外が発生しなかった場合に表示される画面のHTMLファイルの内容は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 | <!DOCTYPE html> <html lang="ja" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>index page</title> </head> <body> <p th:text="${textString}"> ここにtextStringの値が設定されます </p> </body> </html> |
また、エラーを表示させる画面のHTMLファイルの内容は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 | <!DOCTYPE html> <html lang="ja" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>error page</title> </head> <body> <p th:text="${errMsg}"> ここに発生したエラーメッセージが設定されます </p> </body> </html> |
テスト対象プログラムの実行
テスト対象プログラムを実行する前に、まずは以下のファイル「test.txt」をC:\tmp下に配置する。
上記状態で、Spring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスすると、以下の画面(index.html)が表示される。
C:\tmp 下に「test.txt」が無い状態で、Spring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスすると、以下のエラー画面(error.html)が表示される。
JUnitのプログラムの作成と実行
テスト対象のコントローラクラス「DemoController.java」から呼ばれるコンポーネントクラス「DemoComponent.java」で例外を発生させた場合の、JUnitのサンプルプログラムの内容は以下の通り。
下記の「testDemoControllerNotFoundException」「testDemoControllerIOException」メソッドのように、doThrow句を利用することで、指定したメソッドで指定した例外がスローされるようにMock設定できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | package com.example.demo; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.*; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.ui.Model; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; public class DemoControllerTest { /** * テスト対象クラス */ @InjectMocks private DemoController demoController; /** * テスト対象のクラス内で呼ばれるクラスのMockオブジェクト */ @Mock private DemoComponent demoComponent; /** * 前処理(各テストケースを実行する前に行われる処理) */ @Before public void init() { //@Mockアノテーションのモックオブジェクトを初期化 //これを実行しないと@Mockアノテーション、@InjectMocksを付与した //Mockオブジェクトが利用できない MockitoAnnotations.initMocks(this); } /** * DemoControllerクラスのindexメソッドの確認 */ @Test public void testDemoControllerNormal() throws IOException { //demoComponent.getTextStringメソッドでIOExceptionが発生し得るので //メソッドにthrows句を付与している //Mockオブジェクト呼出時の値を設定 doReturn("abcdeテスト").when(demoComponent).getTextString(); //modelオブジェクトを取得し、テスト対象クラスのメソッドを実行 Model model = DemoControllerTestUtil.getModel(); String returnVal = demoController.index(model); //戻り値が"index"であることを確認 assertEquals("index", returnVal); //modelオブジェクトの設定値を確認 //demoComponent.getTextStringが呼ばれた場合は設定したMockの戻り値が設定され、 //エラーメッセージが設定されないことを確認 Map<String, Object> modelValue = model.asMap(); assertEquals("abcdeテスト", modelValue.get("textString")); assertNull(modelValue.get("errMsg")); } @Test public void testDemoControllerNotFoundException() throws IOException { //Mockオブジェクト呼出時の例外を設定 //doThrow句内に例外を設定するが、発生し得ない例外(例:Exception)は設定できない doThrow(new FileNotFoundException()).when(demoComponent).getTextString(); //modelオブジェクトを取得し、テスト対象クラスのメソッドを実行 Model model = DemoControllerTestUtil.getModel(); String returnVal = demoController.index(model); //戻り値が"error"であることを確認 assertEquals("error", returnVal); //modelオブジェクトの設定値を確認 //FileNotFoundExceptionが発生した場合のエラーメッセージ「ファイルが //見つかりませんでした」が設定され、textStringが設定されないことを確認 Map<String, Object> modelValue = model.asMap(); assertEquals("ファイルが見つかりませんでした", modelValue.get("errMsg")); assertNull(modelValue.get("textString")); } @Test public void testDemoControllerIOException() throws IOException { //Mockオブジェクト呼出時の値を設定 //doThrow句内に例外を設定するが、発生し得ない例外(例:Exception)は設定できない doThrow(new IOException()).when(demoComponent).getTextString(); //modelオブジェクトを取得し、テスト対象クラスのメソッドを実行 Model model = DemoControllerTestUtil.getModel(); String returnVal = demoController.index(model); //戻り値が"error"であることを確認 assertEquals("error", returnVal); //modelオブジェクトの設定値を確認 //IOExceptionが発生した場合のエラーメッセージ「入出力例外が発生しました」が //設定され、textStringが設定されないことを確認 Map<String, Object> modelValue = model.asMap(); assertEquals("入出力例外が発生しました", modelValue.get("errMsg")); assertNull(modelValue.get("textString")); } } |
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/junit-mockito-exception/demo
要点まとめ
- 指定したメソッドで指定した例外をスローするには、MockitoライブラリのdoThrowメソッドを利用する。