我有一个包含两个项目的多模块项目:后端和客户端。后端是普通的Spring Boot Rest API,没什么特别的。 client 模块只是使用Rest API的Java库。
后端也使用JSP封装了“ war”作为后端,因此也需要部署到servlet容器中。使用@SpringBootTest仍然可以轻松测试后端。
现在,我想在 client 模块中使用后端模块作为沙箱服务器进行一些集成测试。
要在我添加的客户端模块中使用所有后端类
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
,并将后端配置为带有类的客户端中的测试依赖项
在我的client / src / test / java中,我有一个帮助程序类,用于启动后端模块
@Configuration
public class SandboxServer {
@Bean
public ConfigurableApplicationContext backend() {
return
new SpringApplicationBuilder(BackendApplication.class)
.sources(SandboxServerConfig.class)
.run("spring.profiles.active=sandbox")
}
}
配置文件“沙盒”用于设置测试数据库等。但是我遇到了更多问题。第一个问题是关于文档根目录,因此我对其进行了配置:
public class SandboxServerConfig
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.setDocumentRoot(new File("../backend/src/main/webapp"));
}
}
但是它仍然不起作用,因为Spring不会选择backend / src / main / resources / application.properties
这可能是正确的,因为它不在客户端模块的根类路径中。
所以它实际上不起作用。我想不可能只在集成测试中启动同级模块。
如何实现启动同级spring boot模块进行集成测试?这样的szenario的最佳实践是什么?
答案 0 :(得分:1)
您可以像这样使用TestPropertySource覆盖application.properties
位置:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = BlaApplication.class)
@TestPropertySource(locations="/path/to/backend/src/main/resources/application.properties")
public class ExampleApplicationTests {
}
答案 1 :(得分:0)
我找到了更可靠的解决方案。在我的兄弟项目“前端”中,我有一个组件,当且仅当该服务器尚未运行时,该组件才以集成模式启动后端服务器。
好处:
缺点:
这是我的SandboxServerProcess.class。
import org.springframework.stereotype.Component;
import javax.annotation.*;
import javax.annotation.*;
import java.io.*;
import java.net.*;
import java.util.*;
@Component
@Profile("integration")
public class SandboxServerProcess {
private static final String WAR = "../backend/target/backend.war";
private final static int PORT = 8081;
private boolean startedByMe;
@PostConstruct
public void start() throws Exception {
if (isStarted()) {
return;
}
testWarExists();
packagedWar("start");
if (waitForStartup()) {
startedByMe = true;
return;
}
throw new RuntimeException("Sandbox Server not started");
}
private void testWarExists() {
File file = new File(WAR);
if (!file.exists()) {
throw new RuntimeException("WAR does not exist:" + file.getAbsolutePath());
}
}
@PreDestroy
public void stop() throws IOException {
if (startedByMe) {
packagedWar("stop");
}
}
private void packagedWar(String command) throws IOException {
ProcessBuilder builder = new ProcessBuilder();
builder.environment().put("MODE", "service");
builder.environment().put("SPRING_PROFILES_ACTIVE", "integration");
builder.environment().put("APP_NAME", "backend");
builder.environment().put("PID_FOLDER", "./");
builder.environment().put("LOG_FOLDER", "./");
List<String> commands = new ArrayList<>();
commands.add(WAR);
commands.add(command);
builder.command(commands);
builder.inheritIO();
builder.redirectErrorStream(true);
builder.start();
}
private boolean isStarted() {
try {
Socket socket = new Socket();
InetSocketAddress sa = new InetSocketAddress("localhost", PORT);
socket.connect(sa, 500);
logger.warn("SandboxServer is started");
return true;
} catch (IOException e) {
return false;
}
}
private boolean waitForStartup() throws InterruptedException {
for (int i = 1; i < 30; i++) {
if (isStarted()) {
return true;
}
logger.warn("SandboxServer not yet ready, tries: " + i);
Thread.sleep(1000);
}
return false;
}
}