使用Spock运行集成测试(例如@IntegrationTest
)的最佳方法是什么?我想引导整个Spring Boot应用程序并执行一些HTTP调用来测试整个功能。
我可以使用JUnit(首先运行app然后执行测试):
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
class MyTest {
RestTemplate template = new TestRestTemplate();
@Test
public void testDataRoutingWebSocketToHttp() {
def a = template.getForEntity("http://localhost:8080", String.class)
println a
}
}
但是使用Spock,应用程序无法启动:
@SpringApplicationConfiguration(classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
class MyTestSpec extends Specification {
RestTemplate template = new TestRestTemplate();
def "Do my test"() {
setup:
def a = template.getForEntity("http://localhost:8080", String.class)
expect:
println a
}
}
对于Spock,当然,我在Gradle构建文件中指定了正确的依赖项:
...
dependencies {
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
testCompile 'org.spockframework:spock-spring:0.7-groovy-2.0'
}
...
我错过了什么吗?
答案 0 :(得分:48)
问题是Spock Spring正在寻找Spring的@ContextConfiguration
注释而无法找到它。严格来说,MyTestSpec
用@ContextConfiguration
进行注释,因为它是@SpringApplicationConfiguration
上的元注释,但Spock Spring并未将元注释视为其搜索的一部分。有一个issue来解决这个限制。与此同时,你可以解决它。
@SpringApplicationConfiguration
所做的就是使用特定于引导的上下文加载器自定义@ContextConfiguration
。这意味着您可以通过使用适当配置的@ContextConfiguration
注释来实现相同的效果:
@ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
class MyTestSpec extends Specification {
…
}
更新:只是为了确保它是明确的(并且根据评论,它不是),为此,您需要在类路径上使用org.spockframework:spock-spring
。
答案 1 :(得分:8)
理想情况下,您将使用Spring Boot 1.4+和Spock 1.1+。
Spring Boot添加了许多有用的注释。除了@ ignacio.suay提到的@SpringBootTest
之外,他们还添加了@TestConfiguration
,如果你想在集成测试中使用Spring模拟而不是Mockito,那么它很有用。
如果你将@TestConfiguration
与新的Spock DetachedMockFactory
结合使用,那么你就拥有了将Spock Mocks注入Spring环境所需的所有组件。
我的博客帖子中包含示例代码:Spring Integration Testing with Spock Mocks。
快速而肮脏的是这个
@SpringBootTest
class MyIntegrationTest extends Specification {
@Autowired ExternalRankingService externalRankingServiceMock
def "GetRank"() {
when:
classUnderTest.getRankFor('Bob')
then:
1 * externalRankingServiceMock.fetchRank('Bob') >> 5
}
@TestConfiguration
static class Config {
private DetachedMockFactory factory = new DetachedMockFactory()
@Bean
ExternalRankingService externalRankingService() {
factory.Mock(ExternalRankingService)
}
}
}
<强>更新强>
有a PR可以在Spock中获得更多本机支持,以便将Spock Mocks注入到Spring环境中进行集成测试。新@SpringBean
和@SpringSpy
与@MockBean
和@SpyBean
注释相似
<强>更新强> Spock 1.2现在应该包含这些更改。在文档更新之前,这里是preview of the Spock 1.2 Annotations for Spring Integration Testing。
答案 2 :(得分:3)
在新的Spring Boot版本(1.4)中,而不是使用:
@SpringApplicationConfiguration(classes = MyServer.class)
@WebAppConfiguration
@IntegrationTest
您可以使用
@SpringBootTest(classes = MyServer.class)
您将能够启动应用程序上下文并设置任何依赖项。
有关详细信息,请查看此示例: http://ignaciosuay.com/how-to-do-integration-tests-with-spring-boot-and-spock/
答案 3 :(得分:0)
这是一个启动启动应用程序然后运行spock测试的设置:
class HelloControllerSpec extends Specification {
@Shared
@AutoCleanup
ConfigurableApplicationContext context
void setupSpec() {
Future future = Executors
.newSingleThreadExecutor().submit(
new Callable() {
@Override
public ConfigurableApplicationContext call() throws Exception {
return (ConfigurableApplicationContext) SpringApplication
.run(Application.class)
}
})
context = future.get(60, TimeUnit.SECONDS)
}
void "should return pong from /ping"() {
when:
ResponseEntity entity = new RestTemplate().getForEntity("http://localhost:8080/ping", String.class)
then:
entity.statusCode == HttpStatus.OK
entity.body == 'pong'
}
}
请记住在build.gradle
dependencies {
// other dependencies
testCompile "org.codehaus.groovy:groovy-all:2.2.0"
testCompile "org.spockframework:spock-core:0.7-groovy-2.0"
}