Java 如何测试 Spring-boot 应用程序的主类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46650268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to test main class of Spring-boot application
提问by Patrick
I have a spring-boot
application where my @SpringBootApplication
starter class looks like a standard one. So I created many tests for all my functionalities and send the summary to sonarqubeto see my coverage.
我有一个spring-boot
应用程序,其中我的@SpringBootApplication
入门课程看起来像标准课程。所以我为我的所有功能创建了许多测试,并将摘要发送到sonarqube以查看我的覆盖范围。
For my starter class Sonarqube tells me that I just have 60% coverage. So the average coverage is not good as expected.
对于我的入门课程,Sonarqube 告诉我,我只有 60% 的覆盖率。所以平均覆盖率并不像预期的那么好。
My Test class is just the default one.
我的 Test 课程只是默认课程。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ElectronicGiftcardServiceApplication.class)
public class ElectronicGiftcardServiceApplicationTests {
@Test
public void contextLoads() {
}
}
So how can I test my main class in the starter class of my application?
那么如何在我的应用程序的入门类中测试我的主类呢?
采纳答案by davidxxx
All these answers seem overkill.
You don't add tests to make a metric tool happy.
Loading a Spring context of the application takes time. Don't add it in each developer build just to win about 0.1% of coverage in your application.
Here you don't cover only 1 statementfrom 1 public method. It represents nothing in terms of coverage in an application where thousands of statements are generally written.
所有这些答案似乎都有些矫枉过正。
您不会添加测试来使度量工具满意。
加载应用程序的 Spring 上下文需要时间。不要为了在您的应用程序中赢得大约 0.1% 的覆盖率而在每个开发人员构建中添加它。
在这里,您不会只涵盖1 个公共方法中的1 个语句。在通常写入数千条语句的应用程序中,它不代表任何覆盖范围。
First workaround : make your Spring Boot application class with no bean declared inside. If you have them, move them in a configuration class (for make them still cover by unit test). And then ignore your Spring Boot application class in the test coverage configuration.
第一个解决方法:使您的 Spring Boot 应用程序类没有在内部声明 bean。如果你有它们,把它们移到一个配置类中(让它们仍然被单元测试覆盖)。然后在测试覆盖配置中忽略您的 Spring Boot 应用程序类。
Second workaround : if you really need to to cover the main()
invocation (for organizational reasons for example), create a test for it but an integration test (executed by an continuous integration tool and not in each developer build) and document clearly the test class purpose :
第二种解决方法:如果您确实需要覆盖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[] {});
}
}
回答by fg78nc
You can do something like this
你可以做这样的事情
@Test
public void applicationContextLoaded() {
}
@Test
public void applicationContextTest() {
mainApp.main(new String[] {});
}
回答by marcpa00
I had the same goal (having a test that runs the main() method) and I noticed that simply adding a test method like @fg78nc said will in fact "start" the application twice : once by spring boot test framework, once via the explicit invocation of mainApp.main(new String[] {})
, which I don't find elegant.
我有同样的目标(有一个运行 main() 方法的测试),我注意到简单地添加一个像@fg78nc 所说的测试方法实际上会“启动”应用程序两次:一次是通过 spring boot 测试框架,一次是通过的显式调用mainApp.main(new String[] {})
,我认为这并不优雅。
I ended up writing two test classes : one with @SpringBootTest
annotation and the empty test method applicationContextLoaded(), another one without @SpringBootTest
(only RunWith(SpringRunner.class)
) that calls the main method.
我最终编写了两个测试类:一个带有@SpringBootTest
注释和空测试方法applicationContextLoaded(),另一个没有@SpringBootTest
(仅RunWith(SpringRunner.class)
)调用 main 方法。
SpringBootApplicationTest
SpringBoot 应用测试
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[] {});
}
}
Overall, the application is still started two times, but because there is now two test classes. Of course, with only these two tests methods, it seems overkill, but usually more tests will be added to the class SpringBootApplicationTest
taking advantage of @SpringBootTest
setup.
总的来说,应用程序还是启动了两次,但是因为现在有两个测试类。当然,只有这两种测试方法,似乎有点过分,但通常会SpringBootApplicationTest
利用@SpringBootTest
setup将更多测试添加到类中。
回答by Mariano LEANCE
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>your.awesome.package.Application</mainClass>
</configuration>
</plugin>
If you aim for 100% coverage, one thing you can do is simply not having a main method at all. You still require a class annotated with @SpringBootApplication
but it can be empty.
如果您的目标是 100% 覆盖,您可以做的一件事就是根本没有 main 方法。您仍然需要一个带有注释的类,@SpringBootApplication
但它可以为空。
Be warned though as it has its drawbacks and other tools that rely on main
can break.
但是请注意,因为它有其缺点,并且依赖的其他工具main
可能会损坏。
回答by awgtek
You can Mock SpringApplication
since that is a dependency of the method under test. See how here.
I.e.
您可以模拟,SpringApplication
因为这是被测方法的依赖项。看看这里。IE
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"});
}
}
回答by José Roberto Araújo Júnior
I solved in a different way here. Since this method is there only as a bridge to Spring's run, I annotated the method with @lombok.Generated
and now sonar ignores it when calculating the test coverage.
我在这里以不同的方式解决了。由于此方法仅用作 Spring 运行的桥梁,因此我对该方法进行了注释@lombok.Generated
,现在声纳在计算测试覆盖率时会忽略它。
Other @Generated
annotations, like javax.annotation.processing.Generated
or javax.annotation.Generated
might also work but I can't test now because my issue ticket was closed.
其他@Generated
注释,例如javax.annotation.processing.Generated
或javax.annotation.Generated
可能也有效,但我现在无法测试,因为我的问题单已关闭。
package com.stackoverflow;
import lombok.Generated;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
@Generated
public static void main(String... args) {
SpringApplication.run(Application.class, args);
}
}