简体   繁体   English

Spock 测试中未返回存根 object 方法值

[英]Stubbed object method value not returned in Spock test

I am new to the Spock framework and writing a test case in which I am trying to Mock a class called QueryDatabase我是 Spock 框架的新手,正在编写一个测试用例,我试图在其中模拟一个名为 QueryDatabase 的 class

public class QueryDatabase {

    public BigInteger countRecords(Instant start, Instant end) {

        Flux<CountRecord> countValue = query("select * from users");
        Optional<Object> value = Optional.ofNullable(countValue.blockFirst()).map(CountRecord::getValue);
        BigInteger count = value.filter(BigInteger.class::isInstance)
                    .map(BigInteger.class::cast).orElse(BigInteger.valueOf(0));

        return count
    }
    
    public Flux<CountRecord> query(String query) {
    
    }
}

but the below test case which is to check the value returned by countRecords(Instant, Instant) always gives 0, so that means the value returned in the when section但是下面的测试用例是检查 countRecords(Instant, Instant) 返回的值总是给出 0,这意味着在when部分返回的值

recordCount.query(_) >> Flux.just(CountRecord.builder().value(new BigInteger(133)).build())

is not getting used, seems like recordCount.query(_) >> Flux.empty() also does not have any impact and it always returns the default BigInteger value 0没有被使用,好像recordCount.query(_) >> Flux.empty()也没有任何影响,它总是返回默认的 BigInteger 值 0

def "record count"() {

        given:
        def now = Instant.now()
        def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
        def recordCount = Stub(QueryDatabase)

        when: "query returning empty flux"
        recordCount.query(_) >> Flux.empty()

        then:
        recordCount.countRecords(last10Minutes, now) == 0

        when: "query returning the count record"
        recordCount.query(_) >> Flux.just(CountRecord.builder().value(new BigInteger(133)).build())

        then:
        recordCount.countRecords(last10Minutes, now) == 133

 }

Am I doing anything wrong here?我在这里做错什么了吗?

There are several issues with your code.您的代码有几个问题。

  1. You try to set up some stubbing in the when block您尝试在when块中设置一些存根
  2. You perform your action in the then block您在then块中执行您的操作
  3. You try to redefine stubs您尝试重新定义存根

See Combining Mocking and Stubbing on how this works.请参阅结合 Mocking 和 Stubbing了解其工作原理。

def "record count"() {    
        given:
        def now = Instant.now()
        def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
        def recordCount = Spy(QueryDatabase)

        when: "query returning empty flux"
        def result = recordCount.countRecords(last10Minutes, now)

        then:            
        1 * recordCount.query(_) >> Flux.empty()
        result == 0

        when: "query returning the count record"
        def 2ndResult = recordCount.countRecords(last10Minutes, now) == 133

        then:            
        1 * recordCount.query(_) >> Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
        2ndResult == 133    
 }

Alternatively, you could split it up into a data driven feature或者,您可以将其拆分为数据驱动功能

def "record count"(BigInteger result, Flux input) {    
        given:
        def now = Instant.now()
        def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
        def recordCount = Spy(QueryDatabase)
        recordCount.query(_) >> input

        expect:          
        recordCount.countRecords(last10Minutes, now) == result

        where: 
        result | input
        0      | Flux.empty()
        133    | Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
 }

Normally, you'd order the parameters the other way around, but since the fluxes are so verbose I find this better readable.通常,您会以相反的方式对参数进行排序,但由于通量非常冗长,我发现这更具可读性。

-- EDIT: - 编辑:

I missed that you are trying to stub that same object that you are testing, this can only be done with partial mocking and often indicates, that the code should be refactored.我错过了您正在尝试对您正在测试的相同 object 进行存根,这只能通过部分 mocking来完成,并且通常表明应该重构代码。 So replace Mock / Stub with Spy for partial mocking.因此,将部分 mocking 替换为SpyMock / Stub

What about this way when you override the query method to return an expected Flux .当您覆盖query方法以返回预期的Flux时,这种方式会怎样。 In this case I would recommend to have 2 tests:在这种情况下,我建议进行 2 次测试:

def "record count when empty Flux"() {
        given:
        def now = Instant.now()
        def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
        def recordCount = new QueryDatabase() {
          @Overriden
          public Flux<CountRecord> query(String query) {
            Flux.empty()
          }
        }

        expect:
        recordCount.countRecords(last10Minutes, now) == 0
 }

def "record count when non empty Flux"() {
        given:
        def now = Instant.now()
        def last10Minutes = now.minus(10, ChronoUnit.MINUTES);
        def recordCount = new QueryDatabase() {
          @Overriden
          public Flux<CountRecord> query(String query) {
            Flux.just(CountRecord.builder().value(new BigInteger(133)).build())
          }
        }

        expect:
        recordCount.countRecords(last10Minutes, now) == 133
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM