【发布时间】:2016-02-23 17:40:03
【问题描述】:
在我的一个集成测试中,我似乎遇到了一个棘手的情况。我有一个基于 Spring Boot/Spring MVC 和 Cassandra DB 的 REST 服务器。我正在使用 spring-data-cassandra jar 文件使 POJO 能够通过 CassandraTemplate 通过 CrudRepository 实现插入到数据库中。该应用程序运行良好,我可以进行 REST 调用,并且框架可以正确地将我的表单数据转换为 POJO 并将数据插入数据库中。到目前为止,一切都很好。
我要做的是编写一个执行整个堆栈的集成测试。显然我不想依赖可用的外部数据库,所以我使用 cassandra-unit-spring 中的 EmbeddedCassandra 东西并通过 Spock 测试驱动它。我遇到的问题似乎与 @ContextConfiguration 注释中定义的 SpringApplicationContextLoader 和 @TestExecutionListener 注释中定义的 CassandraUnitTestExecutionListener 类之间的某种排序冲突有关。由于这是一个 Spock 测试,它需要 SpringApplicationContextLoader 类来自动启动 Spring Boot 服务器。但是,它会在 Cassandra 服务器启动之前执行此操作,这会导致集群/会话 bean 无法加载,因为它们显然会在创建后立即联系服务器。我已经尝试了很多让我头晕目眩的组合。我不得不求助于我认为非常丑陋的解决方案。我有一个 setup() 方法,它使用布尔值来确保上下文和 Spring Boot 应用程序只运行一次。我试着把它放在一个 setupSpec() 方法中,每个测试类只运行一次,但这没有用(有些 catch 22 问题)。如果我尝试 @Autowire 上下文,那么它会在 CassandraServer 启动之前被注入。正如我所提到的,我尝试了无数不同的事情。
此解决方案有效,但让我感到困扰的是,我无法仅使用注释和 DI 以更优雅的方式使其工作。此外,@Value 注释字段没有被初始化,这就是为什么我不得不求助于在启动 Tomcat 后通过环境获取服务器端口的原因。非常欢迎任何有关如何以“正确方式”执行此操作的建议。谢谢。
@ActiveProfiles(profiles = ["test"])
@ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = Application.class)
// @WebIntegrationTest("server.port:0") // Pick a random port for Tomcat
@EnableConfigurationProperties
@EmbeddedCassandra
@CassandraDataSet(value = ["cql/createUserMgmtKeySpace.cql", "cql/createUserMgmtTables.cql"], keyspace = "user_mgmt")
@TestExecutionListeners(listeners = [ CassandraUnitTestExecutionListener.class ]) //, DependencyInjectionTestExecutionListener.class ]) //, mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
@Title("Integration test for the lineup ingestion REST server and the Cassandra DAOs.")
public class CassandraSpec extends Specification {
@Shared
ApplicationContext context
@Shared
CQLDataLoader cql
@Shared boolean initialized = false
// This is the server port that Spring picked. We use it in the REST URLs
// @Value('${local.server.port}')
@Shared
int serverPort
def setup() {
if (initialized) {
return
}
System.setProperty("spring.profiles.active", "test")
SpringApplication app = new SpringApplication(CassandraConfig.class)
app.headless = true
context = app.run(Application.class)
assert context
cql = new CQLDataLoader(context.getBean("session"))
serverPort = Integer.parseInt(context.environment.getProperty('server.port'))
println("Tomcat port: ${serverPort}")
initialized = true
}
... test methods here ...
}
【问题讨论】:
标签: spring cassandra spring-boot spring-data spock