Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その11 )( @Rule を使用しているテストを JUnit 5 のテストに書き直す )
概要
記事一覧はこちらです。
- 今回の手順で確認できるのは以下の内容です。
- テストクラス内で @Rule アノテーションを付与しているクラスを JUnit 5 の Extension Model として使用できるように書き直してから、@Rule を使用しているテストを JUnit 5 のテストに書き直します。
参照したサイト・書籍
JUnit 5 User Guide - 5. Extension Model
https://junit.org/junit5/docs/snapshot/user-guide/#extensionsTestWatcher in junit5
https://stackoverflow.com/questions/49037406/testwatcher-in-junit5
目次
- 方針
- MailServerResource クラスを JUnit 5 の Extension としても使用できるようにする
- SecurityMockMvcResource クラスを JUnit 5 の Extension としても使用できるようにする
- 次回へ続く。。。
手順
方針
テストクラス内で @Rule
アノテーションを付与しているクラスは以下の3つでした。
- src/test/java/ksbysample/common/test/rule/mail/MailServerResource.java。ExternalResource クラスを継承して before メソッドと after メソッドを override しています。
- src/test/java/ksbysample/common/test/rule/mockmvc/SecurityMockMvcResource.java。ExternalResource クラスを継承して before メソッドと after メソッドを override しています。
- src/test/java/ksbysample/common/test/rule/db/TestDataResource.java。TestWatcher クラスを継承して starting メソッドと finished メソッドを override しています。
これらを以下の方針で変更します。
- ~Resource というクラス名にしていますが ~Extension というクラス名に変更します。また package を ksbysample.common.test.rule から ksbysample.common.test.extension に変更します。
- JUnit 4 の
@Rule
でも JUnit 5 の Extension でもどちらでも使用できるように変更します。
MailServerResource クラスを JUnit 5 の Extension としても使用できるようにする
まずは src/test/java/ksbysample/common/test/rule/mail/MailServerResource.java から。現在以下の実装ですが、
package ksbysample.common.test.rule.mail; import com.icegreen.greenmail.util.GreenMail; import com.icegreen.greenmail.util.ServerSetup; import org.junit.rules.ExternalResource; import org.springframework.stereotype.Component; import javax.mail.internet.MimeMessage; import java.util.Arrays; import java.util.List; @Component public class MailServerResource extends ExternalResource { private GreenMail greenMail = new GreenMail(new ServerSetup(25, "localhost", ServerSetup.PROTOCOL_SMTP)); @Override protected void before() { greenMail.start(); } @Override protected void after() { greenMail.stop(); } public int getMessagesCount() { return greenMail.getReceivedMessages().length; } public List<MimeMessage> getMessages() { return Arrays.asList(greenMail.getReceivedMessages()); } public MimeMessage getFirstMessage() { MimeMessage message = null; MimeMessage[] receivedMessages = greenMail.getReceivedMessages(); if (receivedMessages.length > 0) { message = receivedMessages[0]; } return message; } }
これを以下のように変更します。
package ksbysample.common.test.extension.mail; import com.icegreen.greenmail.util.GreenMail; import com.icegreen.greenmail.util.ServerSetup; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.rules.ExternalResource; import org.springframework.stereotype.Component; import javax.mail.internet.MimeMessage; import java.util.Arrays; import java.util.List; @Component public class MailServerExtension extends ExternalResource implements BeforeEachCallback, AfterEachCallback { private GreenMail greenMail = new GreenMail(new ServerSetup(25, "localhost", ServerSetup.PROTOCOL_SMTP)); @Override protected void before() { greenMail.start(); } @Override protected void after() { greenMail.stop(); } @Override public void beforeEach(ExtensionContext context) { before(); } @Override public void afterEach(ExtensionContext context) { after(); } public int getMessagesCount() { return greenMail.getReceivedMessages().length; } public List<MimeMessage> getMessages() { return Arrays.asList(greenMail.getReceivedMessages()); } public MimeMessage getFirstMessage() { MimeMessage message = null; MimeMessage[] receivedMessages = greenMail.getReceivedMessages(); if (receivedMessages.length > 0) { message = receivedMessages[0]; } return message; } }
- package を
ksbysample.common.test.rule.mail
→ksbysample.common.test.extension.mail
に変更します(ファイルも移動します)。 - クラス名を
MailServerResource
→MailServerExtension
に変更します。 implements BeforeEachCallback, AfterEachCallback
を追加します。- beforeEach メソッドを override し、中で before メソッドを呼び出します。
- afterEach メソッドを override し、中で after メソッドを呼び出します。
最初に JUnit 4 のテストで正常に動作することを確認します。src/test/java/ksbysample/webapp/lending/helper/mail/EmailHelperTest.java は JUnit 4 のテストとして以下のように実装されていますが、
package ksbysample.webapp.lending.helper.mail; import ksbysample.common.test.extension.mail.MailServerExtension; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.test.context.junit4.SpringRunner; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @RunWith(SpringRunner.class) @SpringBootTest public class EmailHelperTest { @Rule @Autowired public MailServerExtension mailServer; @Autowired private JavaMailSender mailSender; @Autowired private EmailHelper emailHelper; @Test public void testSendSimpleMail() throws Exception { SimpleMailMessage message = new SimpleMailMessage(); message.setFrom("test@sample.com"); message.setTo("xxx@yyy.zzz"); message.setSubject("テスト"); message.setText("これはテストです"); emailHelper.sendSimpleMail(message); assertThat(mailServer.getMessagesCount(), is(1)); MimeMessage receiveMessage = mailServer.getFirstMessage(); assertThat(receiveMessage.getFrom()[0], is(new InternetAddress("test@sample.com"))); assertThat(receiveMessage.getAllRecipients()[0], is(new InternetAddress("xxx@yyy.zzz"))); assertThat(receiveMessage.getSubject(), is("テスト")); assertThat(receiveMessage.getContent(), is("これはテストです")); } @Test public void testSendMail() throws Exception { MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper message = new MimeMessageHelper(mimeMessage); message.setFrom("test@sample.com"); message.setTo("xxx@yyy.zzz"); message.setSubject("テスト"); message.setText("これはテストです"); emailHelper.sendMail(message.getMimeMessage()); assertThat(mailServer.getMessagesCount(), is(1)); MimeMessage receiveMessage = mailServer.getFirstMessage(); assertThat(receiveMessage.getFrom()[0], is(new InternetAddress("test@sample.com"))); assertThat(receiveMessage.getAllRecipients()[0], is(new InternetAddress("xxx@yyy.zzz"))); assertThat(receiveMessage.getSubject(), is("テスト")); assertThat(receiveMessage.getContent(), is("これはテストです")); } }
これを実行するとテストは成功します。
次に JUnit 5 で以下のように書き直してから、
package ksbysample.webapp.lending.helper.mail; import ksbysample.common.test.extension.mail.MailServerExtension; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; @SpringBootTest public class EmailHelperTest { @RegisterExtension @Autowired public MailServerExtension mailServer; @Autowired private JavaMailSender mailSender; @Autowired private EmailHelper emailHelper; @Test void testSendSimpleMail() throws Exception { SimpleMailMessage message = new SimpleMailMessage(); message.setFrom("test@sample.com"); message.setTo("xxx@yyy.zzz"); message.setSubject("テスト"); message.setText("これはテストです"); emailHelper.sendSimpleMail(message); assertThat(mailServer.getMessagesCount()).isEqualTo(1); MimeMessage receiveMessage = mailServer.getFirstMessage(); assertAll( () -> assertThat(receiveMessage.getFrom()[0]).isEqualTo(new InternetAddress("test@sample.com")), () -> assertThat(receiveMessage.getAllRecipients()[0]).isEqualTo(new InternetAddress("xxx@yyy.zzz")), () -> assertThat(receiveMessage.getSubject()).isEqualTo("テスト"), () -> assertThat(receiveMessage.getContent()).isEqualTo("これはテストです") ); } @Test void testSendMail() throws Exception { MimeMessage mimeMessage = mailSender.createMimeMessage(); MimeMessageHelper message = new MimeMessageHelper(mimeMessage); message.setFrom("test@sample.com"); message.setTo("xxx@yyy.zzz"); message.setSubject("テスト"); message.setText("これはテストです"); emailHelper.sendMail(message.getMimeMessage()); assertThat(mailServer.getMessagesCount()).isEqualTo(1); MimeMessage receiveMessage = mailServer.getFirstMessage(); assertAll( () -> assertThat(receiveMessage.getFrom()[0]).isEqualTo(new InternetAddress("test@sample.com")), () -> assertThat(receiveMessage.getAllRecipients()[0]).isEqualTo(new InternetAddress("xxx@yyy.zzz")), () -> assertThat(receiveMessage.getSubject()).isEqualTo("テスト"), () -> assertThat(receiveMessage.getContent()).isEqualTo("これはテストです") ); } }
import org.junit.Test;
→import org.junit.jupiter.api.Test;
に変更します。@RunWith(SpringRunner.class)
を削除します。@Rule
→@RegisterExtension
に変更します。- テストメソッドの
public
を削除します。 MimeMessage receiveMessage = mailServer.getFirstMessage();
を呼び出した後のメールの内容を確認している部分を assertAll を使用するよう変更します。また assertThat は JUnit 4 の org.junit.Assert.assertThat だったので AssertJ の assertThat に変更します。
実行すると、こちらもテストが成功します。
SecurityMockMvcResource クラスを JUnit 5 の Extension としても使用できるようにする
src/test/java/ksbysample/common/test/rule/mockmvc/SecurityMockMvcResource.java は以下の実装ですが、
package ksbysample.common.test.rule.mockmvc; import org.junit.rules.ExternalResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Component; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @Component @ConditionalOnWebApplication public class SecurityMockMvcResource extends ExternalResource { public final String MAILADDR_TANAKA_TARO = "tanaka.taro@sample.com"; public final String MAILADDR_SUZUKI_HANAKO = "suzuki.hanako@test.co.jp"; public final String MAILADDR_KIMURA_MASAO = "kimura.masao@test.co.jp"; public final String MAILADDR_ENDO_YOKO = "endo.yoko@sample.com"; public final String MAILADDR_SATO_MASAHIKO = "sato.masahiko@sample.com"; public final String MAILADDR_TAKAHASI_NAOKO = "takahasi.naoko@test.co.jp"; public final String MAILADDR_ITO_AOI = "ito.aoi@test.co.jp"; @Autowired private WebApplicationContext context; @Autowired private UserDetailsService userDetailsService; public MockMvc authTanakaTaro; public MockMvc authSuzukiHanako; public MockMvc authItoAoi; public MockMvc noauth; @Override protected void before() throws Throwable { // 認証ユーザ用MockMvc ( user = tanaka.taro@sample.com ) UserDetails userDetailsTanakaTaro = userDetailsService.loadUserByUsername(MAILADDR_TANAKA_TARO); this.authTanakaTaro = MockMvcBuilders.webAppContextSetup(this.context) .defaultRequest(get("/").with(user(userDetailsTanakaTaro))) .apply(springSecurity()) .build(); // 認証ユーザ用MockMvc ( user = suzuki.hanako@test.co.jp ) UserDetails userDetailsSuzukiHanako = userDetailsService.loadUserByUsername(MAILADDR_SUZUKI_HANAKO); this.authSuzukiHanako = MockMvcBuilders.webAppContextSetup(this.context) .defaultRequest(get("/").with(user(userDetailsSuzukiHanako))) .apply(springSecurity()) .build(); // 認証ユーザ用MockMvc ( user = ito.aoi@test.co.jp ) UserDetails userDetailsItoAoi = userDetailsService.loadUserByUsername(MAILADDR_ITO_AOI); this.authItoAoi = MockMvcBuilders.webAppContextSetup(this.context) .defaultRequest(get("/").with(user(userDetailsItoAoi))) .apply(springSecurity()) .build(); // 非認証ユーザ用MockMvc this.noauth = MockMvcBuilders.webAppContextSetup(this.context) .apply(springSecurity()) .build(); } }
これを以下のように変更します。
package ksbysample.common.test.extension.mockmvc; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.rules.ExternalResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Component; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @Component @ConditionalOnWebApplication public class SecurityMockMvcExtension extends ExternalResource implements BeforeEachCallback { public final String MAILADDR_TANAKA_TARO = "tanaka.taro@sample.com"; public final String MAILADDR_SUZUKI_HANAKO = "suzuki.hanako@test.co.jp"; public final String MAILADDR_KIMURA_MASAO = "kimura.masao@test.co.jp"; public final String MAILADDR_ENDO_YOKO = "endo.yoko@sample.com"; public final String MAILADDR_SATO_MASAHIKO = "sato.masahiko@sample.com"; public final String MAILADDR_TAKAHASI_NAOKO = "takahasi.naoko@test.co.jp"; public final String MAILADDR_ITO_AOI = "ito.aoi@test.co.jp"; @Autowired private WebApplicationContext context; @Autowired private UserDetailsService userDetailsService; public MockMvc authTanakaTaro; public MockMvc authSuzukiHanako; public MockMvc authItoAoi; public MockMvc noauth; @Override protected void before() { // 認証ユーザ用MockMvc ( user = tanaka.taro@sample.com ) UserDetails userDetailsTanakaTaro = userDetailsService.loadUserByUsername(MAILADDR_TANAKA_TARO); this.authTanakaTaro = MockMvcBuilders.webAppContextSetup(this.context) .defaultRequest(get("/").with(user(userDetailsTanakaTaro))) .apply(springSecurity()) .build(); // 認証ユーザ用MockMvc ( user = suzuki.hanako@test.co.jp ) UserDetails userDetailsSuzukiHanako = userDetailsService.loadUserByUsername(MAILADDR_SUZUKI_HANAKO); this.authSuzukiHanako = MockMvcBuilders.webAppContextSetup(this.context) .defaultRequest(get("/").with(user(userDetailsSuzukiHanako))) .apply(springSecurity()) .build(); // 認証ユーザ用MockMvc ( user = ito.aoi@test.co.jp ) UserDetails userDetailsItoAoi = userDetailsService.loadUserByUsername(MAILADDR_ITO_AOI); this.authItoAoi = MockMvcBuilders.webAppContextSetup(this.context) .defaultRequest(get("/").with(user(userDetailsItoAoi))) .apply(springSecurity()) .build(); // 非認証ユーザ用MockMvc this.noauth = MockMvcBuilders.webAppContextSetup(this.context) .apply(springSecurity()) .build(); } @Override public void beforeEach(ExtensionContext context) { before(); } }
- package を
ksbysample.common.test.rule.mockmvc
→ksbysample.common.test.extension.mockmvc
に変更します。 - クラス名を
SecurityMockMvcResource
→SecurityMockMvcExtension
に変更します。 implements BeforeEachCallback
を追加します。- before メソッドの
throws Throwable
を削除します。 - beforeEach メソッドを override し、中で before メソッドを呼び出します。
現在作成済のテストで SecurityMockMvcExtension を使用しているものは TestDataResource も一緒に使用しているので、TestDataResource を変更してから動作確認します。
次回へ続く。。。
長くなったので次回へ続きます。
履歴
2019/03/09
初版発行。