Как протестировать основной класс приложения Spring -boot

У меня есть приложение spring-boot, где стартовый класс @SpringBootApplication выглядит как стандартный. Поэтому я создал множество тестов для всех своих функций и отправлю резюме в sonarqube, чтобы увидеть мой охват.

Для моего старшего класса Sonarqube говорит мне, что у меня всего 60% покрытия. Таким образом, средний охват не так хорош, как ожидалось.

введите описание изображения здесь

Класс My Test является стандартным.

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

    @Test
    public void contextLoads() {
    }
}

Итак, как я могу проверить свой основной класс в классе стартеров моего приложения?

Ответ 1

Все эти ответы кажутся излишними.
Вы не добавляете тесты, чтобы сделать метрический инструмент счастливым.
Загрузка Spring-контекста приложения занимает много времени. Не добавляйте его в каждую сборку для разработчиков, чтобы выиграть около 0,1% покрытия в вашем приложении.
Здесь вы не рассматриваете только 1 утверждение из 1 открытого метода. Он не представляет ничего с точки зрения охвата в приложении, где обычно пишутся тысячи заявлений.

Первый обходной путь: создайте класс приложения Spring Boot без объявленного компонента внутри. Если они у вас есть, переместите их в класс конфигурации (чтобы они по-прежнему покрывались модульным тестом). А затем проигнорируйте свой класс приложения Spring Boot в конфигурации покрытия теста.

Второй обходной путь: если вам действительно нужно покрыть вызов 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[] {});
   }
}

Ответ 2

Вы можете сделать что-то вроде этого

@Test
public void applicationContextLoaded() {
}

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

Ответ 3

У меня была та же цель (иметь тест, который запускает метод main()), и я заметил, что простое добавление метода теста, такого как @fg78nc, на самом деле "запускает" приложение дважды: один раз при помощи тестовой среды весенней загрузки, один раз через явный вызов mainApp.main(new String[] {}), который я не нахожу элегантным.

В итоге я написал два тестовых класса: один с аннотацией @SpringBootTest и пустой тестовый метод applicationContextLoaded(), другой без @SpringBootTest (только RunWith(SpringRunner.class)), который вызывает основной метод.

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[] {});
  }
}

В целом, приложение все еще запускается два раза, но потому что сейчас есть два тестовых класса. Конечно, только с этими двумя методами тестирования это кажется излишним, но обычно в класс SpringBootApplicationTest будет добавлено больше тестов, использующих преимущества установки @SpringBootTest.

Ответ 4

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

Если вы стремитесь к 100% -ному охвату, одна вещь, которую вы можете сделать, просто не имеет основного метода вообще. Вы все еще требуете класс, аннотированный с помощью @SpringBootApplication, но он может быть пустым.

Будьте осторожны, хотя у него есть свои недостатки, и другие инструменты, которые полагаются на main, могут сломаться.

Ответ 5

Вы можете Mock 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"});
    }

}