如何在规范类之外创建Spock模拟?

时间:2013-05-29 09:48:07

标签: spring unit-testing spock

我们将Spock测试与Spring的@ContextConfiguration结合起来,这样我们就可以在spring上下文中构建bean,然后使用Spock进行实际测试。我们想把spock mocks注入我们的春豆。对于Mockito,有一个扩展,允许您执行以下操作:

 <mockito:mock id="accountService" class="org.kubek2k.account.DefaultAccountService" />

然后将此模拟引用到其他spring bean。 Spock似乎没有这样的扩展。如果您知道如何在Specification类之外创建Mocks,那么再次构建它可能不会太费力。创建我所知道的Spock模拟的唯一方法是:

T Mock(Class<T> type)   
规范中的

。 Spock中是否有一些API可以在不在Specification类中时创建Mocks,所以我可以为Spring上下文创建Spock模拟?

4 个答案:

答案 0 :(得分:6)

目前无法在spec类之外创建模拟(并在另一个spec类中使用它们)。这是一个开放的功能要求。实现它不应该太难,但是需要对spock-core进行一些更改。至少,需要一种方法将模拟对象手动附加到另一个规范实例。也许将面向用户的模拟创建API移出MockingApi基类也是有意义的。

你应该可以将Mockito与Spock一起使用,只要你通过调用返回true的辅助方法来包装then-block中包含的所有验证码(因为Spock会认为它是一个断言) 。类似于then: mockito { /* mockito verifications go here */ }

答案 1 :(得分:5)

找到一个简单的解决方法,在Spring应用程序中使用Spock模拟对象。这里我的spring配置使用了一个模拟basar bean:

@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: "")]
}

答案 2 :(得分:2)

由于Spock 1.1包含SpockMockFactoryBeanspock,因此可以在规范类之外创建模拟。还支持基于XML的配置的DetachedMockFactory命名空间。您可以找到用法示例in the documentation

使用基于Java的配置和@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) } } 的Spring测试如下所示:

<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>

基于XML的配置如下所示:

spock-spring

确保包含testCompile group: 'org.spockframework', name: 'spock-spring', version: '1.1-groovy-2.4-rc-3' 依赖项:

{{1}}

答案 3 :(得分:0)

这与“纯粹的春天”相当直接:

def parentAppCtx = new StaticApplicationContext()
parentAppCtx.beanFactory.registerSingleton("myBean", Mock(MyClass))
parentAppCtx.refresh()
def appCtx = new ClassPathXmlApplicationContext("spring-config.xml", parentAppCtx)

当然,假设您正确分解了Spring配置。 (例如,如果您在"myBean"中重新定义spring-config.xml,则会使用spring-config.xml中的定义,因为ApplicationContext本质上是一个地图,其中包含的最新定义将获胜。)