web-dev-qa-db-ja.com

Spring-bootアプリケーションのメインクラスをテストする方法

spring-bootスタータークラスが標準のように見える@SpringBootApplicationアプリケーションがあります。そのため、すべての機能について多くのテストを作成し、概要を sonarqube に送信して、カバレッジを確認しました。

私のスタータークラスについて、Sonarqubeは、私は60%のカバレッジしかないことを教えてくれます。そのため、平均的なカバレッジは期待どおりではありません。

enter image description here

私のテストクラスはデフォルトです。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ElectronicGiftcardServiceApplication.class)
public class ElectronicGiftcardServiceApplicationTests {

    @Test
    public void contextLoads() {
    }
}

では、アプリケーションのスタータークラスでメインクラスをテストするにはどうすればよいですか?

38
Patrick

これらの答えはすべてやり過ぎのようです。
メトリックツールを満足させるためのテストを追加しないでください。
アプリケーションのSpringコンテキストの読み込みには時間がかかります。アプリケーションのカバレッジの約0.1%を獲得するためだけに、各開発者ビルドに追加しないでください。
ここ1つのパブリックメソッドから1つのステートメントだけをカバーするわけではありません。通常、数千のステートメントが記述されているアプリケーションのカバレッジに関しては何も表していません。

最初の回避策:内部で宣言されたBeanのないSpring Bootアプリケーションクラスを作成します。それらがある場合は、それらを構成クラスに移動します(ユニットテストでカバーできるようにします)。そして、 テストカバレッジ設定でSpring Bootアプリケーションクラスを無視します。

2番目の回避策:main()呼び出し(組織上の理由など)をカバーする必要がある場合は、テストを作成しますが、統合テスト(各開発者ビルドではなく、継続的統合ツールによって実行)とドキュメントを作成します明確にテストクラスの目的:

import org.junit.Test;

// Test class added ONLY to cover main() invocation not covered by application tests.
public class MyApplicationIT {
   @Test
   public void main() {
      MyApplication.main(new String[] {});
   }
}
41
davidxxx

このようなことができます

@Test
public void applicationContextLoaded() {
}

@Test
public void applicationContextTest() {
    mainApp.main(new String[] {});
}
12
fg78nc

私は同じ目標を持っていて(main()メソッドを実行するテストを持っています)、@ fg78ncのようなテストメソッドを追加するだけで、実際にアプリケーションを2回「開始」することに気付きました:1回はスプリングブートテストフレームワークによって、1回はmainApp.main(new String[] {})の明示的な呼び出し。これはエレガントではありません。

私は2つのテストクラスを書いた:1つは@SpringBootTestアノテーションと空のテストメソッドapplicationContextLoaded()、もう1つは@SpringBootTestなし(RunWith(SpringRunner.class)のみ) )mainメソッドを呼び出します。

SpringBootApplicationTest

package example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.boot.test.context.SpringBootTest;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootApplicationTest {

  @Test
  public void contextLoads() {
  }
}

ApplicationStartTest

package example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
public class ApplicationStartTest {
  @Test
  public void applicationStarts() {
    ExampleApplication.main(new String[] {});
  }
}

全体として、アプリケーションはまだ2回起動されますが、2つのテストクラスが存在するためです。もちろん、これらの2つのテストメソッドだけでは過剰に思えますが、通常、@SpringBootTestセットアップを利用して、クラスSpringBootApplicationTestに追加のテストが追加されます。

4
marcpa00
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <mainClass>your.awesome.package.Application</mainClass> 
    </configuration>
</plugin>

100%のカバレッジを目指す場合、できることの1つは、単にメインメソッドをまったく持たないことです。 @SpringBootApplicationアノテーションが付けられたクラスが必要ですが、空にすることもできます。

ただし、欠点があり、mainに依存する他のツールが破損する可能性があるため、注意してください。

2
Mariano LEANCE

SpringApplicationは、テスト対象のメソッドの依存関係であるため、モックできます。 こちら をご覧ください。つまり.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.boot.SpringApplication;

import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;

@RunWith(PowerMockRunner.class)
public class ElectronicGiftcardServiceApplicationTest {

    @Test
    @PrepareForTest(SpringApplication.class)
    public void main() {
        mockStatic(SpringApplication.class);
        ElectronicGiftcardServiceApplication.main(new String[]{"Hello", "World"});
        verifyStatic(SpringApplication.class);
        SpringApplication.run(ElectronicGiftcardServiceApplication.class, new String[]{"Hello", "World"});
    }

}
0
awgtek