我们将Spock测试与Spring的@ContextConfiguration结合起来,这样我们就可以在Spring上下文中构建bean,然后使用Spock进行实际测试。我们想把史波克模型注入我们的春豆。对于Mockito,有一个扩展可以让你做这样的事情:
<mockito:mock id="accountService" class="org.kubek2k.account.DefaultAccountService" />
,然后将此模拟引用到其他spring bean。斯波克似乎没有这样的延伸。如果您知道如何在Specification类之外创建mock,那么构建它可能不会花费太多精力。我所知道的创建Spock mock的唯一方法是:
T Mock(Class<T> type)
在规范。在Spock中是否有一些API可以在不在Specification类内部时创建mock,因此我可以为spring上下文创建Spock mock ?
在规范类之外创建mock(并在另一个规范类中使用它们)目前是不可能的。这是一个开放的特性请求。实现这一点并不难,但需要对spock-core进行一些修改。至少,需要有一种将模拟对象手动附加到另一个规范实例的方法。也许,将面向用户的模拟创建API移出MockingApi
基类也是有意义的。
你应该能够与Spock一起使用Mockito,只要你将包含在然后块中的所有验证代码与调用返回true
的助手方法(因为Spock会认为它是一个断言)包装起来。比如then: mockito { /* mockito verifications go here */ }
在规范类之外创建模拟是可能的,因为Spock 1.1具有DetachedMockFactory
和SpockMockFactoryBean
。还支持用于基于xml的配置的spock
名称空间。您可以在文档中找到使用示例。
使用基于java的配置和DetachedMockFactory
的Spring测试如下:
@ContextConfiguration(classes = [TestConfig, DiceConfig])
class DiceSpec extends Specification {
@Autowired
private RandomNumberGenerator randomNumberGenerator
@Subject
@Autowired
private Dice dice
def "uses the random number generator to generate results"() {
when:
dice.roll()
then:
1 * randomNumberGenerator.randomInt(6)
}
static class TestConfig {
private final mockFactory = new DetachedMockFactory()
@Bean
RandomNumberGenerator randomNumberGenerator() {
mockFactory.Mock(RandomNumberGenerator)
}
}
}
@Configuration
class DiceConfig {
@Bean
Dice dice(RandomNumberGenerator randomNumberGenerator) {
new Dice(randomNumberGenerator)
}
}
基于xml的配置看起来像这样:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:spock="http://www.spockframework.org/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.spockframework.org/spring http://www.spockframework.org/spring/spock.xsd">
<spock:mock id="randomNumberGenerator" class="RandomNumberGenerator"/>
</beans>
确保包含spock-spring
依赖项:
testCompile group: 'org.spockframework', name: 'spock-spring', version: '1.1-groovy-2.4-rc-3'
找到了在Spring应用程序中使用Spock模拟对象的简单解决方法。下面是为基础bean使用模拟的spring配置:
@Configuration @Profile("mocking")
class MockingContext {
@Bean Basar basar(){ new DelegatingBasar() }
}
class DelegatingBasar implements Basar {
@Delegate Basar delegate
}
这里是一个简单的Spock规范,它创建和使用mock:
@Autowired
Basar basar
Basar basarMock
def setup() {
basarMock = Mock(Basar)
basar.delegate = basarMock;
}
def "create a new seller"(User seller) {
given:
basarMock.findAllUsers() >> []
when:
go "/static/sellers.html"
waitFor { $("#newUser") }
$("#newUser").click()
waitFor { $("#basarNumber") }
$("#basarNumber").value(seller.basarNumber)
$("#name").value(seller.name)
$("#lastname").value(seller.lastname)
$("#email").value(seller.email)
$("#saveUser").click()
waitFor { $("#successfullCreated") }
then:
1 * basarMock.saveUser({ newUser ->
newUser.basarNumber == seller.basarNumber
newUser.name == seller.name
newUser.lastname == seller.lastname
newUser.email == seller.email
})
where:
seller << [ new User(basarNumber: "100", name: "Christian", lastname: "", email: ""),
new User(basarNumber: "ABC", name: "", lastname: "", email: "")]
}
对于"pure Spring"来说,这是非常直接的:
def parentAppCtx = new StaticApplicationContext()
parentAppCtx.beanFactory.registerSingleton("myBean", Mock(MyClass))
parentAppCtx.refresh()
def appCtx = new ClassPathXmlApplicationContext("spring-config.xml", parentAppCtx)
当然,这假定您正确地分解了Spring配置。(例如,如果你在spring-config.xml
中重新定义"myBean"
,那么spring-config.xml
中的定义将被使用,因为ApplicationContext
本质上是一个Map,并且最新的定义将被使用。)