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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

Q&A

0回答

3356閲覧

SPring Bootの結合テストで、@MockBeanしたクラスがNullになってしまう

be834194

総合スコア15

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

0グッド

0クリップ

投稿2021/12/19 10:25

前提・実現したいこと

Spring Bootでアプリケーションを作成しているプログラミング初心者です。
ユーザのパスワードとパスワード登録日時をDBへ登録する機能を作成しました。
結合テストで任意のクラスだけMock化する方法についてご教示お願いいたします。

発生している問題・エラーメッセージ

テスト対象のクラスに@Autowiredを、
Mock化したい依存クラスに@MockBeanを付与してテストしたのですが、
NullPointerExceptionが発生してしまいます。

ErrorMeeeage

1java.lang.NullPointerException: Cannot invoke "org.springframework.security.crypto.password.PasswordEncoder.encode(java.lang.CharSequence)" because "this.encoder" is null 2

該当のソースコード

testclass

1@DbUnitConfiguration(dataSetLoader = CsvDataSetLoader.class) 2@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, 3 TransactionalTestExecutionListener.class, 4 DbUnitTestExecutionListener.class}) 5@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 6@RunWith(SpringRunner.class) 7@SpringBootTest(classes = ShareBookRookieApplication.class) 8@Transactional 9public class RegistrationServiceCombinedTest { 10 11 private static final LocalDateTime datetime = LocalDateTime.of(2021, 11, 30, 22, 6, 0); 12 13 private static MockedStatic<LocalDateTime> mock; 14 15 @MockBean 16 PasswordEncoder encoder; 17 18 @Autowired 19 RegistrationService registrationService; 20 21 @BeforeEach 22 void setUp() { 23 MockitoAnnotations.openMocks(this); 24 mock = Mockito.mockStatic(LocalDateTime.class, Mockito.CALLS_REAL_METHODS); 25 mock.when(LocalDateTime::now).thenReturn(datetime); 26 } 27 28 @AfterEach 29 void tearDown() throws Exception { 30 mock.close(); 31 32 } 33 34 @Test 35 @DatabaseSetup(value = "/service/RegistrationService/insert/setup/") 36 @ExpectedDatabase(value = "/service/RegistrationService/insert/expect/",assertionMode=DatabaseAssertionMode.NON_STRICT) 37 void registerMemberでユーザとPW変更履歴が1件ずつ登録される() throws Exception{ 38 RegistrationForm form = new RegistrationForm(); 39 form.setUserName("田中"); 40 form.setPassword("tanaka"); 41 when(encoder.encode(form.getPassword())).thenReturn("tanaka"); 42 43 registrationService.registerMember(form); 44 45 } 46 47}

以下、テストクラスに関連するクラスになります。

RegistrationService

1@Service 2@Transactional 3public class RegistrationService { 4 5 private final RegistrationMapper registrationMapper; 6 7 private final ChangeEntitySharedService changeEntityService; 8 9 private final PasswordEncoder encoder; 10 11 public RegistrationService(RegistrationMapper registrationMapper, 12 ChangeEntitySharedService changeEntityService, 13 PasswordEncoder encoder) { 14 this.registrationMapper = registrationMapper; 15 this.changeEntityService = changeEntityService; 16 this.encoder = encoder; 17 } 18 19 public void registerMember(RegistrationForm form) { 20 //パスワードのハッシュ化 21 form.setPassword(encoder.encode(form.getPassword())); 22 //accountテーブルへインサート 23 registrationMapper.insertMember(changeEntityService.setToAccount(form)); 24 //password_historyデーブルへインサート 25 registrationMapper.insertPasswordHistory(changeEntityService.setToHistory(form)); 26 27 } 28 29 public void updatePasswordMember(RegistrationForm form) { 30 //パスワードのハッシュ化 31 form.setPassword(encoder.encode(form.getPassword())); 32 //accountテーブルへのアップデート 33 registrationMapper.updatePassword(changeEntityService.setToAccount(form)); 34 //password_historyデーブルへインサート 35 registrationMapper.insertPasswordHistory(changeEntityService.setToHistory(form)); 36 37 } 38 39}

ChangeEntitySharedService

1@Service 2public class ChangeEntitySharedService { 3 public Account setToAccount(RegistrationForm form){ 4 Account account = new Account(); 5 account.setUserName(form.getUserName()); 6 account.setPassword(form.getPassword()); 7 account.setRole("ROLE_USER"); 8 return account; 9 } 10 11 public PasswordHistory setToHistory(RegistrationForm form) { 12 PasswordHistory history = new PasswordHistory(); 13 history.setUserName(form.getUserName()); 14 history.setPassword(form.getPassword()); 15 history.setUseFrom(LocalDateTime.now()); 16 return history; 17 } 18 19}

RegistrationForm

1public class RegistrationForm { 2 3 @NotBlank 4 private String userName; 5 6 @NotBlank 7 private String password; 8 9 public String getUserName() { 10 return userName; 11 } 12 13 public void setUserName(String userName) { 14 this.userName = userName; 15 } 16 17 public String getPassword() { 18 return password; 19 } 20 21 public void setPassword(String password) { 22 this.password = password; 23 } 24 25}

BeanConfig

1@Configuration 2public class BeanConfig { 3 @Bean 4 PasswordEncoder passwordEncoder() { 5 return new BCryptPasswordEncoder(); 6 } 7 8}

RegistrationMapper

1 <insert id = "insertMember" parameterType="com.rookie.sharebook.entity.Account"> 2 INSERT INTO 3 ACCOUNT(USERNAME, PASSWORD, ROLE) 4 VALUES( 5 #{userName}, 6 #{password}, 7 #{role}) 8 </insert> 9 10 <insert id = "insertPasswordHistory" parameterType="com.rookie.sharebook.entity.PasswordHistory"> 11 INSERT INTO 12 PASSWORD_HISTORY(USERNAME, PASSWORD, USEFROM) 13 VALUES( 14 #{userName}, 15 #{password}, 16 #{useFrom}) 17 </insert>

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

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

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

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

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

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問