基于 Spring Boot 的微服务集成测试
Posted
技术标签:
【中文标题】基于 Spring Boot 的微服务集成测试【英文标题】:Integration testing Spring Boot based Microservices 【发布时间】:2015-06-24 15:18:22 【问题描述】:我已经阅读了许多有关使用 Spring Boot 和 RESTful 服务的指南,其中许多包含有关运行单元测试的信息,其中最著名的是“使用 Spring Boot 构建应用程序”。但是,我还没有看到任何示例说明如何对使用/依赖于其他 Spring Boot 应用程序的 Spring Boot 应用程序进行单元测试,这在云微服务架构中很常见。因此,例如,我们有以下 Spring Boot 服务:
服务中介, 适配器1, 适配器2
ServiceMediator 调用 Adapter1 或 Adapter2,具体取决于输入。
有没有办法在 Spring JUnit 测试中启动和测试 ServiceMediator 之前启动 Spring Boot 服务 Adapter1 和 Adapter2?
【问题讨论】:
您是在谈论单元测试来模拟 serviceMediator 的位置,还是要进行集成测试来确定调用真实服务的位置? 我说的是集成测试。 我想这真的取决于你如何定义它。我只是在寻找一种以自动化方式测试本地机器上所有服务的方法。因此,有没有办法在测试中介之前启动中介所依赖的服务? 我找到了一种方法来做到这一点,但我不知道这是否是最好的方法。我愿意接受更好的方法,所以如果有人有更好的方法,请分享。在测试中介之前,我正在使用 ProcessBuilder 启动适配器。 【参考方案1】:package controller;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.net.URL;
import mediator.CLPApplication;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = CLPApplication.class)
@WebAppConfiguration
@IntegrationTest()
public class ControllerTest
@Value("$adapter.dependency.jar.location")
private String adapterDependencyJarLocation;
@Value("$adapter.dependency.jar.name")
private String adapterDependencyJarName;
@Value("$adapter.url")
private String adapterURL;
@Value("$mediator.url")
private String mediatorURL;
private URL mediator;
private URL adapter;
private RestTemplate template;
Process process = null;
@Before
public void setUp() throws Exception
adapter = new URL(adapterURL);
template = new TestRestTemplate();
//
// Start the Atomic adapter
//
System.out.println(adapterDependencyJarLocation);
System.out.println("Starting Adapter");
try
process = new ProcessBuilder("java", "-jar", adapterDependencyJarName)
.directory(new File(adapterDependencyJarLocation)).start();
// Try connecting 5 times with a 5 second pause between each
// to see if it started.
Thread.sleep(5000);
for(int i = 0; i <= 5; i++)
try
System.out.println("Testing to see if Adapter is up");
template.getForEntity(adapter.toString(), String.class);
System.out.println("Adapter Started");
break;
catch(RestClientException rce)
System.out.println("It's not up yet");
Thread.sleep(5000);
catch (Exception e)
e.printStackTrace();
@Test
public void testMediator() throws Exception
mediator = new URL(mediatorURL);
System.out.println("Calling Mediator");
ResponseEntity<String> response = template.getForEntity(mediator.toString(), String.class);
System.out.println(response.getBody());
// Getting back JSON, so check to see if it starts with an open bracket
assertThat(response.getBody(), Matchers.startsWith(""));
@After
public void tearDown()
if(process != null)
process.destroy();
【讨论】:
【参考方案2】:process-exec-maven-plugin 可能会有所帮助,因为它允许在 pre-integration-test 阶段(作为标准 Spring Boot 应用程序)启动多个 java 进程,并在集成后测试阶段。
注意:集成测试应该在 integration-test 阶段运行,因为 maven-failsafe-plugin 应该配置为spring-boot-maven-plugin see。 然后运行我们的集成测试 verify 或更高版本的 maven Lifecycle 应该是目标,因为 integration-test 阶段实际上位于 package 和 验证生命周期see Default Lifecycles。
以下 maven (pom.xml) 配置对我有用:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.5.RELEASE</version>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
<configuration>
<skip>$integration-tests.skip</skip>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
<configuration>
<skip>$integration-tests.skip</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<skip>$integration-tests.skip</skip>
<includes>
<include>**/*IT.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.bazaarvoice.maven.plugins</groupId>
<artifactId>process-exec-maven-plugin</artifactId>
<version>0.7</version>
<executions>
<execution>
<id>switchboard-process</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
<configuration>
<name>accounts-service</name>
<workingDir>/../../micro-service</workingDir>
<waitForInterrupt>false</waitForInterrupt>
<arguments>
<argument>java</argument>
<argument>-jar</argument>
<argument>$basedir/../micro-service/target/micro-service-$project.version-exec.jar</argument>
</arguments>
</configuration>
</execution>
<!--Stop all processes in reverse order-->
<execution>
<id>stop-all</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop-all</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
在 test.java 文件夹中有一个集成测试类 (WebServerIT):
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = WebServerApp.class)
@WebIntegrationTest("server.port:0")
public class WebServerIT
@Autowired
private WebApplicationContext webServerAppContext;
private MockMvc webServerMockMvc;
@Before
public void setUp()
System.out.println("the test is set up");
webServerMockMvc = MockMvcBuilders.webAppContextSetup(webServerAppContext).build();
/**
* This test calls the WebServer's endpoint (/accounts/123456789) which in turn calls the micro-service rest api
* which is started using the process-exec-maven-plugin, otherwise the test would fail.
*/
@Test
public void testWebServerInteractionWithMicroService() throws Exception
this.webServerMockMvc.perform(get("/accounts/123456789"))
.andExpect(status().isOk());
【讨论】:
以上是关于基于 Spring Boot 的微服务集成测试的主要内容,如果未能解决你的问题,请参考以下文章
使用 Eureka 服务集成测试 Spring Boot 服务