MockMvc Userdetails AuthenticationPrincipal

今回は、Junitでテスト時にコントローラでUserDetails@AuthenticationPrincipalで受け取る方法についてみていきたいと思います。

困っていたところ

Controller

@Controller
public SomeController {

 @Autowired
 private SomeService someService;

 @GetMapping("/some")
 public String some(@AuthenticationPrincipal CustomUserDetails user) {
  someService.someMethod(user.getSomeData());
  return "some/page";
 }
}
  • 上記のコードは例です。

上記のように「AuthenticationPrincipal」アノテーションがついているUserDetailsからSomeDataを取得してServiceに渡していました。

Test

public class SomeControllerTest {

    @InjectMocks
    private SomeController someController;

    @Mock
    private SomeService someService;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = MockMvcBuilders.standaloneSetup(itemEndpoint)
                .build();
    }

    @Test
    public void someTest() throws Exception {
        when(someService.someMethod(anyString())).thenReturn("some"); // こちら

        mockMvc.perform(get("/some")).
                .andExpect(status().isOk());
    }
}

「こちら」となっている箇所でモック化するときにNullPointExceptionとなり、調べたところコントローラのCustomUserDetailsがNullで「user.getSomeData()」するときにエラーが発生していました。

UserDetailsのモック

public class SomeControllerTest {

    @InjectMocks
    private SomeController someController;

    @Mock
    private SomeService someService;

    private MockMvc mockMvc;



    private HandlerMethodArgumentResolver putAuthenticationPrincipal = new HandlerMethodArgumentResolver() {
        @Override
        public boolean supportsParameter(MethodParameter parameter) {
            return parameter.getParameterType().isAssignableFrom(CustomUserDetails.class);
        }

        @Override
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                      NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
            return new CustomUserDetails(…);
        }
    };

    @BeforeEach
    public void setup() {
        mockMvc = MockMvcBuilders.standaloneSetup(itemEndpoint)
                .setCustomArgumentResolvers(putAuthenticationPrincipal)
                .build();
    }

    @Test
    public void someTest() throws Exception {
        when(someService.someMethod(anyString())).thenReturn("some");

        mockMvc.perform(get("/some")).
                .andExpect(status().isOk());
    }
}
  • 赤文字と表示している箇所が追加したところで、使用しているカスタムのUserDetailsのクラス名を指定すればOKです。
  • その後は定義したResolverをMockMvcんみ登録する必要があるので、登録しました。

これで正常に動きました。

終わりに

SpringSecurityテストの「WithAnonymousUser」「WithUserDetails」「WithMockUser」などのアノテーションもありますが、今回の状況とは違ったのでパスしました。機会があれば調べたいと思います。

Junit難しい。。。

コメントを残す