微服务应用程序代表了一个相互通信的单个服务的集合。开发人员在一个或多个服务上工作以实现新功能或错误修复是很常见的。在运行时需要的其他服务中测试这些变化,需要所有的依赖关系都可用。Gradle Docker compose插件使得启动一个应用程序堆栈并将其绑定到测试任务的任务执行生命周期中变得非常容易。
我们将选择Java和测试框架JUnit 5来编写集成测试。在列表2中,你可以看到测试用例使用孵化的JDK HTTP客户端调用预期的服务端点。你将通过构建时传入的系统属性使服务端点的主机名和端口可用。断言逻辑会在测试用例的每次迭代中验证HTTP调用的预期响应。
src/test/java/com/bmuschko/ApplicationIntegrationTest.java
package com.bmuschko;
import jdk.incubator.http.HttpClient;
import jdk.incubator.http.HttpRequest;
import jdk.incubator.http.HttpResponse;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import java.io.IOException;
import java.net.URI;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ApplicationIntegrationTest {
private static final String WEB_SERVICE_HOST = System.getProperty("web.host");
private static final Integer WEB_SERVICE_PORT = Integer.getInteger("web.tcp.5000");
private static final String WEB_SERVICE_URI = "http://" + WEB_SERVICE_HOST + ":" + WEB_SERVICE_PORT + "/";
@ParameterizedTest(name = "can resolve application URL {0} times")
@ValueSource(ints = { 1, 2, 3 })
void canResolveApplicationUrl(int times) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(WEB_SERVICE_URI))
.GET()
.build();
HttpResponse response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandler.asString());
assertTrue(response.body().contains(String.format("Welcome to this awesome page! You've visited me %s times.", times)));
}
}
清单2.测试类调用服务端点
清单3演示了Java插件的应用,以及使用Compose作为test 任务的夹具所需的必要配置。方便的方法isRequiredBy 在composeUp 的帮助下建立了一个任务依赖关系。 dependsOn的帮助下建立了对composeDown 的任务依赖,并通过 finalizedBy.此外,方法exposeAsSystemProperties 自动向测试JVM进程提供系统属性.host 和.tcp. 。欲了解更多信息,请参见插件文档。
plugins {
id 'java'
}
dockerCompose {
isRequiredBy(project.tasks.test)
exposeAsSystemProperties(project.tasks.test)
}
清单3.使用Compose作为测试任务的夹具
JDK的HTTP客户端已从Java 9中引入。你必须明确配置构建,以使用孵化模块进行编译和测试执行。此外,构建必须声明模块对JUnit 5的依赖性,并指出测试任务应该使用这个特定的测试框架。
sourceCompatibility = 9
targetCompatibility = 9
def httpclientModuleJvmArg = '--add-modules=jdk.incubator.httpclient'
compileTestJava {
options.compilerArgs.add(httpclientModuleJvmArg)
}
test {
useJUnitPlatform()
jvmArgs httpclientModuleJvmArg
}
repositories {
mavenCentral()
}
dependencies {
def junitJupiterVersion = '5.1.1'
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitJupiterVersion"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
}
清单4.为测试任务设置JUnit 5
从命令行执行./gradlew test ,以测试驱动集成测试。下面的控制台输出应该给你一个粗略的概述,即哪些任务被运行,以什么顺序运行。
$ ./gradlew test --console=verbose
> Task :compileJava NO-SOURCE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :compileTestJava
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :composeUp
> Task :test
> Task :composeDown
BUILD SUCCESSFUL in 1m 57s
4 actionable tasks: 4 executed
总结
Gradle在管理Compose应用程序堆栈方面做得非常出色。凭借其内置功能,Compose操作可以毫不费力地集成到任务执行生命周期中。在我接下来的一篇博文中,我计划将构建级方法与从测试类实现(例如TestContainers提供的)管理容器的方法进行比较。