【问题标题】:Object comparison in spock test failsspock 测试中的对象比较失败
【发布时间】:2012-11-12 19:05:11
【问题描述】:

我正在尝试使用 spock 为我拥有的方法编写测试。

方法是这样的——

InvoiceView getInvoiceDetailView(String invoiceNumber, Boolean isNew) {
    InvoiceView detailView;
    if (isNew) {
        newInvoiceDao.em = billingEm;
        //call InvoiceDao
        List<GroovyRowResult> invoiceSummaryRowResult = billingAdmin.rows(InvoiceQueries.GET_NEW_INVOICE_SUMMARIES_BY_NUMBER, [invoiceNumber:invoiceNumber]);
        List<GroovyRowResult> invoiceDetailsRowResult = billingAdmin.rows(InvoiceQueries.GET_NEW_INVOICE_DETAILS_BY_NUMBER, [invoiceNumber:invoiceNumber]);
        InvoiceModel invoiceModel = newInvoiceDao.getInvoice(invoiceNumber);
        detailView = new InvoiceView(invoice:invoiceModel,
                                             summary:invoiceSummaryRowResult,
                                            details:invoiceDetailsRowResult);
} ...

我的测试只是试图断言,当调用此方法时将 true 作为 isNew 参数的值传入,将返回一个有效的 InvoiceView 对象。

在我的 spock 测试中,我创建了一些我希望从方法中返回的对象:

def expectedInvoiceModel = new InvoiceModel()
def expectedInvoiceSummaryRowResult = new ArrayList<GroovyRowResult>()
def expectedInvoiceDetailsRowResult = new ArrayList<GroovyRowResult>()

def expectedInvoiceView = new InvoiceView(invoice:expectedInvoiceModel,
                                          summary:expectedInvoiceSummaryRowResult,
                                          details:expectedInvoiceDetailsRowResult)

我还模拟了我将要调用的 dao 对象:

def setup() {
    ...
    service.billingAdmin = Mock(Sql)
    ...
}

所以终于到了 Spock 夹具上。我已将有问题的比较行注释掉并进行了解决。我的问题是 - 为什么我的“then”块中的第一行失败?

def "getInvoiceDetailView returns valid InvoiceView for new invoice"() {
    given:
        service.billingAdmin.rows(InvoiceQueries.GET_NEW_INVOICE_SUMMARIES_BY_NUMBER, [invoiceNumber:invoiceNumber]) >> expectedInvoiceSummaryRowResult
        service.billingAdmin.rows(InvoiceQueries.GET_NEW_INVOICE_DETAILS_BY_NUMBER, [invoiceNumber:invoiceNumber]) >> expectedInvoiceDetailsRowResult
        service.newInvoiceDao.getInvoice(_) >> expectedInvoiceModel

    when:
        def result = service.getInvoiceDetailView(invoiceNumber, true)
    then:
        //result == expectedInvoiceView -- Why doesn't this work?
        result.invoice == expectedInvoiceModel
        result.summary == expectedInvoiceSummaryRowResult
        result.details == expectedInvoiceDetailsRowResult
}

【问题讨论】:

    标签: java unit-testing groovy spock


    【解决方案1】:

    显然,根据类InvoiceViewequals 方法,对象不相等。或者该类可能没有声明 equals 方法,并且对象不相同(根据 Object.equals)。

    【讨论】:

    • 这就是我认为的问题所在。我在类定义上方粘贴了规范的 groovy 注释,但这没有帮助,比较检查仍然失败。不知道如何解决这个...
    • 只需在调试器中运行测试即可。
    【解决方案2】:

    扎卡里。

    您没有正确模拟 getInvoice 方法。尽管您通过两个参数调用它,但您的模拟调用只需要一个(“_”字符接受任何参数,但将与一个完全匹配)。由于没有匹配的模拟方法,对 getInvoice 的调用将返回默认值 null,从而使您的测试失败。

    您应该执行以下操作以使您的测试通过:

    service.newInvoiceDao.getInvoice(_, _) >> expectedInvoiceModel
    

    我写了一个小测试来更清楚地说明这一点。给定以下类:

    private static class StringUtils {
        public String concatenate(String a, String b) {
            return a + b;
        }
    }
    

    以下测试将失败:

    def "concatenation should work!"() {
        given: 
        StringUtils su = Mock()
        su.concatenate(_) >> "ab"
    
        when:
        def result = su.concatenate("a", "b")
    
        then:
        result == "ab" 
    }
    

    请注意,我的模拟方法只需要一个参数:

    su.concatenate(_) >> "ab"
    

    这是显示我返回空值的错误消息:

    Condition not satisfied:
    
    result == "ab"
    |      |
    null   false
    

    但是,如果我正确地模拟了 concatenate 方法,测试就会成功:

    su.concatenate(_, _) >> "ab"
    

    【讨论】:

    • 感谢卡洛斯的回答,但我认为这不是解决方案。我不确定为什么将该语句移到 then 块中会有所不同,但我试了一下,没有骰子。
    • 抱歉,我认为这与 Spock 模拟的混乱范围定义有关。
    • 至少不直观。在你理解之后,它是有道理的,但是在我的团队中与 Spock 一起工作的所有开发人员在第一次尝试时都遇到了问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多