1
4

More than 3 years have passed since last update.

@RunWith(PowerMockRunner.class)と@RunWith(SpringRunner.class)と@SpringBootTestの共存方法

Last updated at Posted at 2021-08-11

環境

  • Java 11.02
  • Spring Boot 2.4.9
  • powermock-module-junit4:2.0.9
  • powermock-api-mockito2:2.0.7

概要

@RunWith(PowerMockRunner.class)@RunWith(SpringRunner.class)を同時に使いたい。
しかし、@RunWithには複数クラスを指定することはできない。
そのため、以下のように@PowerMockRunnerDelegateを使う。

build.gradle
dependencies {
    testImplementation 'org.powermock:powermock-module-junit4:2.0.9'
    testImplementation 'org.powermock:powermock-api-mockito2:2.0.7'
}
@PrepareForTest({SampleServiceImpl.class})
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@SpringBootTest
public class SampleServiceImplTest {
}

しかしこれでテストを実行すると以下のエラーが出る。

java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: java.security.NoSuchAlgorithmException: class configured for TrustManagerFactory: sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory not a TrustManagerFactory

以下の記事では、必要なconfigurationだけ読むようにすれば解決するだろうと書いてあるが、面倒くさい。
https://stackoverflow.com/questions/50307402/exception-using-springrunner-with-powermockrunner

解決

以下の記事の通りに、@PowerMockIgnore({ "javax.net.ssl.*" })を付けたらエラーは出なくなり、テストが通るようになった。
https://www.nerd.vision/post/nosuchalgorithmexception-when-using-powermockito

@PrepareForTest({ SampleServiceImpl.class })
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({ "javax.net.ssl.*" })
@SpringBootTest
public class SampleServiceImplTest {

    @Test
    public void mainTest() throws Exception {
        SampleServiceImpl mockInstance = PowerMockito.spy(new SampleServiceImpl());
        PowerMockito.when(mockInstance, MemberMatcher.method(SampleServiceImpl.class, "private_method_name"))
                .withArguments(Mockito.anyInt()).thenReturn(0);

        mockInstance.main(Mockito.anyString());

        assertEquals(0, mockInstance.private_method_name());
    }
}

まだ問題が

PowerMockitoを使ってprivateメソッドをテストする際、そのメソッド内で、Autowiredされた他のクラスのオブジェクトが呼ばれていると、そいつがjava.lang.NullPointerExceptionを起こす。

以下にコードの例を記載する。

テスト対象のクラス

SampleServiceImpl
@Service
public class SampleServiceImpl implementes SampleService {

    @Autowired
    SampleRepository sampleRepository;

    public void main(String message) {
        System.out.println(fetchAll());
    }

    // ここをMockにしたい
    private List<SampleModel> fetchAll() {
        // これがNullPointerExceptionを起こす。そもそもMockにしてるのに何でこいつが呼び出されるの?
        return sampleRepository.findAll();
    }
}

Repository

SampleRepository
public interface SampleRepository extends JpaRepository<SampleModel, Long> {
}

Model

SampleModel
@Getter
@Entity
@Table(name="sample_tables")
public class SampleModel {
    @Id
    private Long id;
    private String text;
    private Boolean status;
}

テストコード

@PrepareForTest({ SampleServiceImpl.class })
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({ "javax.net.ssl.*" })
@SpringBootTest
public class SampleServiceImplTest {

  @Test
  public void mainTest() throws Exception {
        List<SampleModel> SamplesMock = SamplesMock();

        // spyにしているが、mockでも結果は同じ
        SampleServiceImpl SampleServiceImpl = PowerMockito.spy(new SampleServiceImpl());
        // 以下の行でjava.lang.NullPointerExceptionが発生する
        PowerMockito.doReturn(SamplesMock).when(SampleServiceImpl, "fetchAll");
  }
}

原因と解決方法

アノテーションが問題であった。
@RunWith(PowerMockRunner.class)@SpringBootTestが共存しているとこの問題が起きる。
そこで、以下のように@PowerMockIgnorejavax.xml.*org.xml.*を追記することで解決した。

@PrepareForTest({SampleServiceImpl.class})
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({
        "javax.net.ssl.*",
        "javax.xml.*",
        "org.xml.*"
})
@SpringBootTest
public class SampleServiceImplTest {
}

以下にIssueが上がっているが、Powermock 2.0.0とjdk9以上で起こるバグっぽい。。

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4