Spring

@ParameterizedTest사용할 때 java.lang.NoSuchMethodException 발생 시

dodop 2022. 2. 16. 21:09

 

 

@ParameterizedTest를 사용하여 여러가지 경우를 테스트 하려고 할 때 

java.lang.NoSuchMethodException 예외가 발생하게 되었다. 

(cannot invoke non-static-method)

 

 

 

원인 
@ParameterizedTest
@MethodSource("lottoGame")
@DisplayName("추첨 번호를 이용하여 올바를 로또 결과를 반환한다.")
void match_counts_with_winning_numbers(LottoGame lottoGame,
    WinningLotto winningLotto, int actual) {
    //given

    //when
    LottoResult lottoResult = lottoGame.draw(winningLotto);

    //then
    assertEquals(lottoResult.getResult().get(MatchType.FOUR), actual);
    assertEquals(lottoResult.getResult().get(MatchType.FIVE), actual);
}

private Stream<Arguments> lottoGame() {
    return Stream.of(
        Arguments.of(new LottoGame(Arrays.asList(
            new Lotto(new FixNumberStrategy(Arrays.asList(1, 3, 4, 5, 7, 9))),
            new Lotto(new FixNumberStrategy(Arrays.asList(2, 3, 4, 5, 6, 8))))
        ), new WinningLotto(new HashSet<>(Arrays.asList(1, 2, 3, 4, 5, 6)), 1), 1)
    );
}

해당 예외는 버전이 맞지 않을 때, 파라미터가 맏지 않을 때에도 발생할 수 있지만, 예제를 이용하여 상황을 재구성해서 보면 ParameterizedTest에 사용될 메소드인 lottoGame이 static이 아니라서 발생 되었다. (@MethodSource에 사용될 팩토리 메소드는 static이어야 한다.)

 

ArgumentSource를 보면 ArgumentProvider는 top-level 클래스 또는 static nested class에 선언되어야 한다 고 나타나있다. 

 

 

 

해결 ①
@ParameterizedTest
@MethodSource("lottoGame")
@DisplayName("추첨 번호를 이용하여 올바를 로또 결과를 반환한다.")
void match_counts_with_winning_numbers(LottoGame lottoGame,
    WinningLotto winningLotto, int actual) {
    //given

    //when
    LottoResult lottoResult = lottoGame.draw(winningLotto);

    //then
    assertEquals(lottoResult.getResult().get(MatchType.FOUR), actual);
    assertEquals(lottoResult.getResult().get(MatchType.FIVE), actual);
}

private static Stream<Arguments> lottoGame() {
    return Stream.of(
        Arguments.of(new LottoGame(Arrays.asList(
            new Lotto(new FixNumberStrategy(Arrays.asList(1, 3, 4, 5, 7, 9))),
            new Lotto(new FixNumberStrategy(Arrays.asList(2, 3, 4, 5, 6, 8))))
        ), new WinningLotto(new HashSet<>(Arrays.asList(1, 2, 3, 4, 5, 6)), 1), 1)
    );
}

첫번째 해결방법은 해당 메소드에 static을 넣어주면 해결된다. 

 

 

해결 ②
@TestInstance(Lifecycle.PER_CLASS)
class Test{
    @ParameterizedTest
    @MethodSource("lottoGame")
    @DisplayName("추첨 번호를 이용하여 올바를 로또 결과를 반환한다.")
    void match_counts_with_winning_numbers(LottoGame lottoGame,
        WinningLotto winningLotto, int actual) {
        //given

        //when
        LottoResult lottoResult = lottoGame.draw(winningLotto);

        //then
        assertEquals(lottoResult.getResult().get(MatchType.FOUR), actual);
        assertEquals(lottoResult.getResult().get(MatchType.FIVE), actual);
    }

    private Stream<Arguments> lottoGame() {
        return Stream.of(
            Arguments.of(new LottoGame(Arrays.asList(
                new Lotto(new FixNumberStrategy(Arrays.asList(1, 3, 4, 5, 7, 9))),
                new Lotto(new FixNumberStrategy(Arrays.asList(2, 3, 4, 5, 6, 8))))
            ), new WinningLotto(new HashSet<>(Arrays.asList(1, 2, 3, 4, 5, 6)), 1), 1)
        );
    }
}

두번째 해결방법은 테스트 클래스 (top-level)에 @TestInstance(Lifecycle.PER_CLASS)를 지정해주어 해당 메서드를 사용할 수 있게 해준다. 

 

 

( 참고한 사이트 )

https://github.com/junit-team/junit5/issues/1452

 

ParameterizedTest not playing nice with Collections · Issue #1452 · junit-team/junit5

@ParameterizedTest @ArgumentsSource( PluginProvider.class ) void codeQuality( Collection<Class<?>> toApply ) { Project project = ProjectBuilder.builder().build(); toApply.forEach( proje...

github.com

https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests-sources-ArgumentsSource

 

JUnit 5 User Guide

Although the JUnit Jupiter programming model and extension model will not support JUnit 4 features such as Rules and Runners natively, it is not expected that source code maintainers will need to update all of their existing tests, test extensions, and cus

junit.org

https://youtrack.jetbrains.com/issue/IDEA-246118

 

IntelliJ incorrectly warns about missing method for JUnit5 @MethodSource : IDEA-246118

When using @MethodSource for a @ParametrizedTest … IntelliJ incorrectly warns about a missing method, if the method is not on the same class. However, it is possible with JUnit5 to have the method (static or non-static) on a different class level, even o

youtrack.jetbrains.com