在 spring 中跳过 VPN DNS 可用性启动时的集成测试
Skipping integration tests in spring boot on VPN DNS availability
我有一个中等重量的 spring 启动服务,在正常流程上启动需要 10-15 秒,在 retry/failover 流程上失败需要 (1-2) 分钟。这对我的业务流程来说没问题,这也是我期望健康服务的表现方式。
我有集成测试(运行 我的服务中有一些端到端的流程),只能在测试机器(或开发机器)连接到特定的服务器时测试实际的集成状态VPN.
如果我没有连接到 VPN,我想自动跳过集成测试。
考虑以下代码
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Server.class}, // auto scans a bunch of components
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) // slow loading context
public class IntegrationTest {
@BeforeClass
public static void beforeClass() {
Assume.assumeTrue(DnsTool.vpnConnected()); // fast failing test
}
@Test
public void testIntegration() {
// some test logic
}
}
当假设通过时,我的测试 运行,一切都很好。
当假设失败时,我的测试会被跳过,但只有在尝试加载昂贵的上下文之后才会跳过。
如何避免测试套件的 运行ning 时间过长?
我尝试过的事情:
- 子类化
SpringJUnit4ClassRunner
,并覆盖 isTestMethodIgnored
。
- 添加一个
TestExecutionListener
,并在beforeTestClass
中抛出假设异常
这些在 Spring 上没有留下任何印象,并且以任何方式加载了上下文。
我没有尝试的事情:
- Lazy init 附带 2.2.X 我认为 spring 的下一个稳定版本。
Lazy init 可能会解决我的问题,但我觉得应该有一些简单的 spring-test/junit 修复我所缺少的。
在此先感谢您的帮助。
对我来说,这听起来像是您根本不应该在测试中做的事情。
测试(至少恕我直言)应该检查业务案例并假设环境已设置并准备就绪。
也许值得将此功能委派给构建工具和 CI。
示例:
在 Maven(或您使用的任何构建工具)中定义一个配置文件,它将 运行 需要 VPN 的集成测试。定义将 运行 所有其余集成测试的配置文件。
如果某些系统 属性 可用,请激活配置文件。
在 CI 工具(如 Jenkins)中作为 CI 的一部分甚至在 运行 maven 之前,运行 将检查 VPN 连接的脚本。根据结果设置系统属性和 运行 具有这些属性的 maven。将加载所需的配置文件,所有测试/仅不需要 VPN 的测试将 运行.
更新
如果您需要从 Spring 开始工作(看起来您更喜欢这种方式),
Spring 有一个特殊的注解叫做 @IfProfileValue
默认情况下,它与系统属性匹配,如果值不匹配,测试将被忽略。
它看起来像这样(请注意,您也可以将此注释放在 class 上,然后它将适用于 class 中的所有测试方法):
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTestClass {
@IfProfileValue(name = "os.name", values = {"Linux"})
@Test
public void testMe() {
// will run only in linux, otherwise
// won't even try to load an
// application context
....
}
}
这涵盖了当您从外部解析 VPN 连接和 运行 使用 属性 进行测试时的情况。但是,如果你想在 java 中实现 VPN 连接检查,这个注释是不够的,因为它只能与 Java 系统属性一起使用,所以为了使用自定义逻辑,你需要实现 org.springframework.test.annotation.ProfileValueSource
:
public class VPNConnectivityProfileValueSource implements ProfileValueSource {
private String vpnEnabled = "true";
public VPNConnectivityProfileValueSource () {
// no spring context is available here
ClassPathResource resource = new ClassPathResource("vpn-config.properties");
if (resource.exists()) {
// read the VPN address,
//
//this.testProps = PropertiesLoaderUtils.loadProperties(resource);
// invoke your utility, check the connectivity, etc.
this.vpnEnabled = ...
}
}
@Override
public String get(String key) {
// this is important method,
if(key.equals("vpn.enabled") {
return this.vpnEnabled;
}
else return System.getProperty(key);
}
}
最后一件事是让测试知道 ProfileValueSource:
为此,您在测试中添加了另一个特殊注释:
@ProfileValueSourceConfiguration(VPNConnectivityProfileValueSource.class)
总而言之,测试可能如下所示:
@RunWith(SpringRunner.class)
@SpringBootTest
@ProfileValueSourceConfiguration(VPNConnectivityProfileValueSource.class)
@IfProfileValue(name = "vpn.enabled", value = "true")
public class MyTestClass {
@Test
public void testMe() {
....
}
}
我提到的所有 classes/annotations 都在包 org.springframework.test.annotation
中
我有一个中等重量的 spring 启动服务,在正常流程上启动需要 10-15 秒,在 retry/failover 流程上失败需要 (1-2) 分钟。这对我的业务流程来说没问题,这也是我期望健康服务的表现方式。
我有集成测试(运行 我的服务中有一些端到端的流程),只能在测试机器(或开发机器)连接到特定的服务器时测试实际的集成状态VPN.
如果我没有连接到 VPN,我想自动跳过集成测试。
考虑以下代码
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Server.class}, // auto scans a bunch of components
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) // slow loading context
public class IntegrationTest {
@BeforeClass
public static void beforeClass() {
Assume.assumeTrue(DnsTool.vpnConnected()); // fast failing test
}
@Test
public void testIntegration() {
// some test logic
}
}
当假设通过时,我的测试 运行,一切都很好。 当假设失败时,我的测试会被跳过,但只有在尝试加载昂贵的上下文之后才会跳过。
如何避免测试套件的 运行ning 时间过长?
我尝试过的事情:
- 子类化
SpringJUnit4ClassRunner
,并覆盖isTestMethodIgnored
。 - 添加一个
TestExecutionListener
,并在beforeTestClass
中抛出假设异常
这些在 Spring 上没有留下任何印象,并且以任何方式加载了上下文。
我没有尝试的事情:
- Lazy init 附带 2.2.X 我认为 spring 的下一个稳定版本。
Lazy init 可能会解决我的问题,但我觉得应该有一些简单的 spring-test/junit 修复我所缺少的。
在此先感谢您的帮助。
对我来说,这听起来像是您根本不应该在测试中做的事情。 测试(至少恕我直言)应该检查业务案例并假设环境已设置并准备就绪。
也许值得将此功能委派给构建工具和 CI。
示例:
在 Maven(或您使用的任何构建工具)中定义一个配置文件,它将 运行 需要 VPN 的集成测试。定义将 运行 所有其余集成测试的配置文件。 如果某些系统 属性 可用,请激活配置文件。
在 CI 工具(如 Jenkins)中作为 CI 的一部分甚至在 运行 maven 之前,运行 将检查 VPN 连接的脚本。根据结果设置系统属性和 运行 具有这些属性的 maven。将加载所需的配置文件,所有测试/仅不需要 VPN 的测试将 运行.
更新
如果您需要从 Spring 开始工作(看起来您更喜欢这种方式),
Spring 有一个特殊的注解叫做 @IfProfileValue
默认情况下,它与系统属性匹配,如果值不匹配,测试将被忽略。
它看起来像这样(请注意,您也可以将此注释放在 class 上,然后它将适用于 class 中的所有测试方法):
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTestClass {
@IfProfileValue(name = "os.name", values = {"Linux"})
@Test
public void testMe() {
// will run only in linux, otherwise
// won't even try to load an
// application context
....
}
}
这涵盖了当您从外部解析 VPN 连接和 运行 使用 属性 进行测试时的情况。但是,如果你想在 java 中实现 VPN 连接检查,这个注释是不够的,因为它只能与 Java 系统属性一起使用,所以为了使用自定义逻辑,你需要实现 org.springframework.test.annotation.ProfileValueSource
:
public class VPNConnectivityProfileValueSource implements ProfileValueSource {
private String vpnEnabled = "true";
public VPNConnectivityProfileValueSource () {
// no spring context is available here
ClassPathResource resource = new ClassPathResource("vpn-config.properties");
if (resource.exists()) {
// read the VPN address,
//
//this.testProps = PropertiesLoaderUtils.loadProperties(resource);
// invoke your utility, check the connectivity, etc.
this.vpnEnabled = ...
}
}
@Override
public String get(String key) {
// this is important method,
if(key.equals("vpn.enabled") {
return this.vpnEnabled;
}
else return System.getProperty(key);
}
}
最后一件事是让测试知道 ProfileValueSource:
为此,您在测试中添加了另一个特殊注释:
@ProfileValueSourceConfiguration(VPNConnectivityProfileValueSource.class)
总而言之,测试可能如下所示:
@RunWith(SpringRunner.class)
@SpringBootTest
@ProfileValueSourceConfiguration(VPNConnectivityProfileValueSource.class)
@IfProfileValue(name = "vpn.enabled", value = "true")
public class MyTestClass {
@Test
public void testMe() {
....
}
}
我提到的所有 classes/annotations 都在包 org.springframework.test.annotation