| tags |
|
|||
|---|---|---|---|---|
| projects |
|
本指南将帮助您了解创建Spring应用程序的过程。
您将构建一个简单的Spring的应用和并用JUnit测试它。您可能已经知道如何编写和运行应用程序中各个类的单元测试,因此对于本指南,我们将集中讨论使用Spring Test和Spring Boot特性来测试Spring和你的代码代码之间的交互。你将从一个简单地测试应用程序上下文加载成功,并继续测试只是Web层使用Spring的`MockMvc`。
为你的Spring应用程序创建一个新控制器:
src/main/java/hello/HomeController.java
link:complete/src/main/java/hello/HomeController.java[role=include]|
Note
|
以上例子不指定 GET 和 PUT, POST 等等,因为 @RequestMapping 默认映射所有的HTTP操作。使用 @RequestMapping(method=GET) 缩小这种映射。
|
虽然可以将此服务打包为一个传统的 WAR 文件用于部署到外部应用服务器,更为简单的方法是创建了一个独立的应用程序。通过一个 good old Java main() 方法,你能将一切打包成为一个单一的克执行 JAR 文件。在这一过程中,您使用Spring的提供的 Tomcat servlet容器作为HTTP运行时,而不是将它部署的到一个外部实例在中。
src/main/java/hello/Application.java
link:complete/src/main/java/hello/Application.java[role=include]日志输出显示。应用程序应该在几秒钟内启动和运行。
既然应用程序正在运行,你就可以测试它。如果它正在运行你可以加载主页 http://localhost:8080。但是,为了让您对应用程序在进行更改时更有信心,您需要自动化测试。
您可以做的第一件事是编写一个简单明了的检查测试,如果应用程序上下文不能启动,它将失败。先在测试范围加Spring Test作为一个依赖项到你的pom.xml文件。如果你正在使用Maven:
pom.xml
link:complete/pom.xml[role=include]如果你使用的是Gradle:
build.gradle
link:complete/build.gradle[role=include]然后创建一个使用了 @RunWith 和 @SpringBootTest 注释的测试用例和一个空的试验方法:
src/test/java/hello/ApplicationTest.java
package hello;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTest {
@Test
public void contextLoads() throws Exception {
}
}@SpringBootTest 注释告诉Spring Boot去寻找主配置类(例如一个带有 @SpringBootApplication 的类),用以启动一个Spring应用程序上下文。你可以在你的IDE或在命令行中运行这个测试 (mvn test or gradle test) ,它应该会通过。为了使自己确信上下文正在创建控制器,可以添加断言:
src/test/java/hello/SmokeTest.java
link:complete/src/test/java/hello/SmokeTest.java[role=include]@Autowired 注释是由Spring 解释,控制器会在测试方法运行前注入的。我们使用的是 AssertJ (assertThat() 等等)来表达测试断言。
|
Note
|
Spring测试支持的一个很好的特性是在测试之间缓存应用程序上下文,所以如果在测试用例中有多个方法,或者具有相同配置的多个测试用例,它们只会产生一次启动应用程序的成本。你可以通过 @DirtiesContext 注释控制缓存使用。
|
有这样的检查是很好的,但是我们也应该编写一些测试来验证我们的应用程序的行为。为了做到这一点,我们可以启动应用程序并监听它在生产中所做的连接,然后发送HTTP请求并断言响应。
src/test/java/hello/HttpRequestTest.java
link:complete/src/test/java/hello/HttpRequestTest.java[role=include]注意 webEnvironment=RANDOM_PORT 用随机端口启动服务器(避免在测试环境中的冲突是有用的),与 @LocalServerPort 注射端口的用法。还要注意Spring Boot已自动为你提供了一个 TestRestTemplate 注释,所有你所要做的就是 @Autowired 它。
另一个有用的方法是根本不启动服务器,但只测试下面的层,其中Spring处理传入的HTTP请求并将其交给控制器。这样,几乎可以使用完整的堆栈,并且您的代码将被调用的方式与处理一个真正的HTTP请求完全相同,但不需要花时间启动服务器。这样做,我们将使用Spring的 MockMvc ,我们可以得到用 @AutoConfigureMockMvc 注解的测试用例:
src/test/java/hello/ApplicationTest.java
link:complete/src/test/java/hello/ApplicationTest.java[role=include]在这个测试中,启动了完整的Spring应用程序上下文,但没有服务器。我们可以缩小测试只是Web层采用 @WebMvcTest :
src/test/java/hello/WebLayerTest.java
@RunWith(SpringRunner.class)
@WebMvcTest
link:complete/src/test/java/hello/WebLayerTest.java[role=include]测试断言是在先前的情况一样,但这里Spring Boot只实例化Web层,而不是整个山下文。你甚至可以在具有多个控制器的一个应用中只实例化其中一个控制器,例如使用 `@WebMvcTest(HomeController.class)`的情况下
到目前为止,我们的` HomeController `非常简单,没有依赖。我们可以通过引入一个额外的组件来存储问候语,从而使它更加贴近现实。在一个新控制器中:
src/main/java/hello/GreetingController.java
link:complete/src/main/java/hello/GreetingController.java[role=include]然后
src/main/java/hello/GreetingService.java
link:complete/src/main/java/hello/GreetingService.java[role=include]服务依赖项将自动注入Spring到控制器中(因为构造函数签名)。 你可以像这样使用 @WebMvcTest 测试控制器
src/test/java/hello/WebMockTest.java
link:complete/src/test/java/hello/WebMockTest.java[role=include]我们用 @MockBean 创建并注入模拟的 GreetingService (如果你不这样做应用程序上下文不能启动),我们将使用 Mockito 判断他的值。
祝贺你!你刚刚开发出一种Spring的应用,并使用JUnit和带有Spring Boot隔离Web层和负载的特殊应用环境 MockMvc 注解的Spring 来测试它。