質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
JUnit

JUnitは、Javaで開発されたプログラムのユニットテストを行うためのアプリケーションフレームワークです。簡単にプログラムのユニットテストを自動化することができ、結果もわかりやすく表示されるため効率的に開発時間を短縮できます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

ユニットテスト

ユニットテストは、システムのテスト手法の一つで、個々のモジュールを対象としたテストの事を指します。対象のモジュールが要求や性能を満たしているか確認する為に実行します。

Q&A

解決済

1回答

10559閲覧

URLクラスのMockがうまくいかない

Y.Takahashi

総合スコア5

JUnit

JUnitは、Javaで開発されたプログラムのユニットテストを行うためのアプリケーションフレームワークです。簡単にプログラムのユニットテストを自動化することができ、結果もわかりやすく表示されるため効率的に開発時間を短縮できます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

ユニットテスト

ユニットテストは、システムのテスト手法の一つで、個々のモジュールを対象としたテストの事を指します。対象のモジュールが要求や性能を満たしているか確認する為に実行します。

0グッド

0クリップ

投稿2020/05/26 02:06

編集2020/05/26 03:03

Junitテストで外部接続のMockをしたいのですが、
java.lang.AbstractMethodError: Missing implementation of resolved method 'abstract java.net.URLConnection openConnection(java.net.URL)' of abstract class java.net.URLStreamHandler.
が発生し上手くいきません。
環境はjdk-1.8.0、Junit5です。

以下が、Mock対象のソースになります。

public void openConnection() throws MalformedURLException, IOException { //接続するURLを指定する URL url = new URL( protocol, host, port, filePath ); //コネクションを取得する urlConn = (HttpURLConnection) url.openConnection(); urlConn.setConnectTimeout(10000); // HTTPメソッドを設定する urlConn.setRequestMethod(httpMethod); // リスエストとボディ送信を許可する urlConn.setDoOutput(true); // レスポンスのボディ受信を許可する urlConn.setDoInput(true); // コネクション接続 urlConn.connect(); // 読み込み・書き込みストリーム取得 ps = new PrintStream(urlConn.getOutputStream()); reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); }

以下がJunitソースになります。

@PrepareForTest({ URL.class }) public class SampleTest { @Mock HttpURLConnection urlConn; @Mock PrintStream ps; @Mock BufferedReader reader; @InjectMocks Sample sample = new Sample(); @Test public void function() throws Exception{ ReserveInformation rsvinfo = new ReserveInformation(); URL u = PowerMockito.mock(URL.class); PowerMockito.whenNew(URL.class).withArguments(anyString(), anyString(), anyInt(), anyString()).thenReturn(u); HttpURLConnection huc = PowerMockito.mock(HttpURLConnection.class); PowerMockito.when(u.openConnection()).thenReturn(huc); PowerMockito.when(huc.getResponseCode()).thenReturn(200); sample.openConnection(); } }

java初心者のため、細かい説明もいただけると助かります。

よろしくお願いいたします。

追記
Gradleのバージョンは6.3で、Junit5は5.6.0、PowerMockはpowermock-mockito2-2.0.2-full.jarを使用しております。
Mockitoにつきましてはgradle.buildを見た感じ2.xだと思われます。

以下がgradle.buildになります。
私自身はgradleに明るくなく他の方に書いてもらったもののため、説明はできません。

plugins { id 'org.springframework.boot' version '2.2.6.RELEASE' id 'io.spring.dependency-management' version '1.0.9.RELEASE' id 'java' } configurations { developmentOnly runtimeClasspath { extendsFrom developmentOnly } compileOnly { extendsFrom annotationProcessor } // SLF4Jを使わない設定 all*.exclude module : 'spring-boot-starter-logging' } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-activemq' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web-services' compileOnly 'org.projectlombok:lombok' runtimeOnly 'org.postgresql:postgresql' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.projectlombok:lombok' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } // Log4J2を使うので追加 implementation 'org.springframework.boot:spring-boot-starter-log4j2' // OpenAPI用 implementation 'io.springfox:springfox-swagger2:2.8.0' implementation 'io.springfox:springfox-swagger-ui:2.8.0' implementation 'org.openapitools:jackson-databind-nullable:0.1.0' implementation 'org.apache.activemq:activemq-pool:5.9.0' compile fileTree(dir: 'lib', include: '*.jar') testCompile "org.mockito:mockito-core:2.+" } test { useJUnitPlatform() }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rubytomato

2020/05/26 02:33

Mockito、PowerMock、JUnit5のそれぞれの正確なバージョンと、プロジェクトにMavenかGradleを使用されている場合は、pom.xml or build.gradleの内容を教えてください。
Y.Takahashi

2020/05/26 03:04

ご質問内容について追記しました。 他にご不明な点がございましたらご質問ください。
rubytomato

2020/05/26 06:29

2点お伺いします。 > compile fileTree(dir: 'lib', include: '*.jar') > testCompile "org.mockito:mockito-core:2.+" これらの行で "powermock-mockito2-2.0.2-full.jar" と Mockito 2.xをプロジェクトの依存関係に加えている、ということだと思いますが、この理解でいいでしょうか? それと、SampleTestクラスのfunctionメソッドにはassertやverifyなどテスト結果を確認するコードがないようですが、例外が起きなければテスト成功ということでしょうか?
Y.Takahashi

2020/05/26 07:29

> これらの行で "powermock-mockito2-2.0.2-full.jar" と Mockito 2.xをプロジェクトの依存関係に加え> ている、ということだと思いますが、この理解でいいでしょうか? ご認識の通りです。 ただ compile fileTree(dir: 'lib', include: '*.jar') についてはテスト対象外のクラスで使用しているjarがいくつか存在しています。 > それと、SampleTestクラスのfunctionメソッドにはassertやverifyなどテスト結果を確認するコードが> ないようですが、例外が起きなければテスト成功ということでしょうか? 結果確認についてはエラーまたは例外が起きなければテスト成功という認識で間違いございません。
guest

回答1

0

ベストアンサー

直接的な回答にはなりませんでしたが、参考になればと思います。

テスト環境について

Spring Boot 2.2.6で組み込まれるテスト関係のライブラリにMockito 3.1.0があります。
なので、build.gradleでMockito 2.xを組み込もうとしても反映されていない可能性があります。
プロジェクトの依存関係を確認してみてください。

testCompile "org.mockito:mockito-core:2.+"

次にpowermock-mockito2-2.0.2-full.jarで、プロジェクトにPowerMock 2.xを組み込んでいるということですが、PowerMock 2.xには以下の制限があります。

1つ目は『JUnit 5.xをサポートしていない』という点

https://github.com/powermock/powermock/wiki/Getting-Started

Currently PowerMock supports JUnit and TestNG. There are three different JUnit test executors available, one for JUnit 4.4-4.12, one for JUnit 4.0-4.3. The test executor for JUnit 3 is not avaliable since PowerMock 2.0.

2つ目は『Mockito 3.xをサポートしていない」という点

https://github.com/powermock/powermock/wiki/Mockito#supported-versions

PowerMock version 2.0.0 and upper has support of Mockito 2. PowerMock version 1.7.0 and upper has experimental support of Mockito 2.

以上のことから、現在のテスト環境でPowerMockを利用することは適切ではないと思いますが、絶対に使えないかと聞かれると、そこまではわかりません。

ですが、サポートされていないライブラリを使うことはリスクが高いので検討してください。

テストしやすいコードに修正する

PowerMockを使わずにMockitoだけでモック化するには、質問にご提示のコードでは難しいと思います。
なので、コードの修正が可能であれば、この機にテストしやすいコードに修正することをお勧めします。
以下は修正の一例です。と言ってもメソッドの引数にURLを受け取るだけです。

java

1public void openConnection(URL url) throws IOException { 2 //接続するURLを指定する 3 //URL url = new URL(protocol, host, port, filePath); 4 5 //コネクションを取得する 6 urlConn = (HttpURLConnection) url.openConnection(); 7 urlConn.setConnectTimeout(10000); 8 9 // HTTPメソッドを設定する 10 urlConn.setRequestMethod("GET"); 11 // リスエストとボディ送信を許可する 12 urlConn.setDoOutput(true); 13 // レスポンスのボディ受信を許可する 14 urlConn.setDoInput(true); 15 // コネクション接続 16 urlConn.connect(); 17 18 // 読み込み・書き込みストリーム取得 19 ps = new PrintStream(urlConn.getOutputStream()); 20 reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream())); 21}

テストコードは以下の通りです。URLのインスタンス化処理を外に出したことで、モック化の対象を限定できます。

java

1public class SampleTest { 2 3 @Mock 4 HttpURLConnection urlConn; 5 6 @BeforeEach 7 public void setup() { 8 MockitoAnnotations.initMocks(this); 9 } 10 11 @Test 12 public void test() throws Exception { 13 14 String data = "{ \"name\": \"john\", \"age\": 20 }"; 15 InputStream in = new ByteArrayInputStream(data.getBytes("utf-8")); 16 when(urlConn.getInputStream()).thenReturn(in); 17 18 when(urlConn.getResponseCode()).thenReturn(200); 19 20 OutputStream out = new ByteArrayOutputStream(); 21 when(urlConn.getOutputStream()).thenReturn(out); 22 23 URLStreamHandler stubUrlHandler = new URLStreamHandler() { 24 @Override 25 protected URLConnection openConnection(URL u) throws IOException { 26 // モック化したHttpURLConnectionを返す 27 return urlConn; 28 } 29 }; 30 31 URL url = new URL("http", "dummyhost", 9999, "/data.json", stubUrlHandler); 32 33 Sample sample = new Sample(); 34 sample.openConnection(url); 35 sample.read(); 36 sample.closeConnection(); 37 } 38 39}

テストのためにコードは修正できない

テストのため(だけ)にコードを修正できないという理由もあると思います。
その場合は無理にモック化するのではなくモックサーバーを利用するという方法があります。
ユニットテストで使えそうなモックサーバーにMockServer、WireMockなどがあります。
何が使えそうかは別途お調べください。

モックサーバーを利用することでテストコードでPowerMockやMockitoを使う必要はなくなると思いますが、その代わりモックサーバーに期待する振る舞いをさせるための設定などが必要になります。

投稿2020/05/26 08:48

rubytomato

総合スコア1752

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Y.Takahashi

2020/05/27 01:29

お教えくださったもの参考にテスト対処のソースとテストソースを修正し、無事成功しました。 Mockはバージョンも気にしないといけないのですね。 今回は本当に助かりました、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問