unit-testing - Spock - 如何检查 Spy 对象上的方法调用计数?

标签 unit-testing spock

我很难让这个 spock 测试发挥作用。

我有一个 Spring repo/DAO 类,它多次调用存储过程。我正在尝试编写一个单元测试来验证 SP 是否被调用“x”次(3 次调用 createSP() 方法)。

public class PlanConditionRepositoryImpl{

    ....

    public void write() {
        for (int i=0; i<3; i++) {
            createSP(new ConditionGroup(), new Condition()).call();
        }
    }

    protected StoredProcedure<Void> createSP(ConditionGroup planConditionGroup, Condition planCondition) {
        return new StoredProcedure<Void>()
                .jdbcTemplate(getJdbcTemplate())
                .schemaName(SCHEMA_NAME);
    }
}       

但是下面的实现并没有这样做。如何实现调用计数检查?或者如何避免调用 createSP() 方法的实际实现。

def write(){
    def repo = Spy(PlanConditionRepositoryImpl){
        createSP(_, _) >> Spy(StoredProcedure){
            call() >> {
                //do nothing
            }
        }
    }
    when:
    repo.write()

    then:
    3 * repo.createSP(_, _)
}

这就是我使用 hack 解决它的方法。但是有没有一种解决方案使用 Spock 的基于交互的测试而不引入额外的变量呢?

def "spec"() {
    given:
    def count = 0
    def spy = Spy(PlanConditionRepositoryImpl){
        createSP(_, _) >> {count++}
    }

    when:
    spy.write()

    then:
    count == 3
}

最佳答案

您需要的是部分模拟,请查看 docs 。然而,正如我所说,部分模拟基本上是不好的做法,并且可能表明设计不好:

(Think twice before using this feature. It might be better to change the design of the code under specification.)

关于部分模拟:

// this is now the object under specification, not a collaborator
def persister = Spy(MessagePersister) {
  // stub a call on the same object
  isPersistable(_) >> true
}

when:
persister.receive("msg")

then:
// demand a call on the same object
1 * persister.persist("msg")

以下是测试的编写方式:

@Grab('org.spockframework:spock-core:1.0-groovy-2.4')
@Grab('cglib:cglib-nodep:3.1')

import spock.lang.*

class Test extends Specification {
    def "spec"() {
        given:    
        def mock = Mock(StoredProcedure)
        def spy = Spy(PlanConditionRepositoryImpl) 

        when:
        spy.write()

        then:
        3 * spy.createSP() >> mock
        3 * mock.run()
    }
}

class PlanConditionRepositoryImpl {

    void write() {
        for (int i = 0; i < 3; i++) {
            createSP().run()
        }
    }

    StoredProcedure createSP() {
        new StoredProcedure()    
    }
}

class StoredProcedure {
    def run() {}
}

关于unit-testing - Spock - 如何检查 Spy 对象上的方法调用计数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33157664/

相关文章:

c# - 在 Winforms 中使用 IoC 时如何不绕过容器

java - JUnit - 从类型转换返回模拟对象

testing - Grails 服务的 Spock 测试中的交互太少

java - 将模拟添加到集合适用于 .times,而不适用于 for 循环

grails - 何时使用 mock 以及何时使用带有 spock 的 stub?

exception - 使用Spock转换空对象时出现问题

c# - Moq - 是否可以在不使用 It.IsAny 的情况下设置模拟

unit-testing - 使用模拟对象编写可维护的单元测试

java - 在 Mockito 中 stub 方法时,我应该使用原始实例还是 stub 实例进行测试?

java - 如何使用 eclipse 和 gradle 对 Java 项目运行 Spock 测试?