Spock - 返回固定值不按预期工作

时间:2015-09-07 17:05:18

标签: java groovy spock stub

如果我使用的条款不正确,我必须先道歉。我只使用groovy / java进行自动化任务(Gradle),而且我不具备多年提供生产级软件的经验。

所以,我所面临的挑战如下:我有一个规范试图测试返回字符串是否符合预期(几乎与this相同)。

def "pretty print returns correct string"() {
    setup:
    X509Certificate stubCert = Stub()
    stubCert.getSubjectDN().toString() >> "Test"

    when:
    def output = X509CertificateUtils.prettyPrint(stubCert)

    then:
    output == "Subject: Test"
}

然而,区别在于我的方法约束返回一个Principal对象,而它的对象是toString(),我真的想要存根。我以为我在上面做的正确,但它没有给出我期望的结果。

这是我的帮助班。

import java.security.cert.X509Certificate

class X509CertificateUtils {

    static def prettyPrint(X509Certificate x509Certificate) {
        return "Subject: ${x509Certificate.getSubjectDN()}"
    }
}

如果我运行此测试,则会收到以下错误:

output == "Subject: Test"
|      |
|      false
|      38 differences (20% similarity)
|      Subject: (Mock for )t(ype 'Principal' named 'dummy')
|      Subject: (Tes------)t(-----------------------------)
Subject: Mock for type 'Principal' named 'dummy'

感谢任何帮助。

2 个答案:

答案 0 :(得分:6)

只需创建第二个存根:

X509Certificate stubCert = Stub()
Principal princ = Stub()
princ.toString() >> "Test"
stubCert.getSubjectDN() >> princ

答案 1 :(得分:3)

Spock有一些伪造物体的方法。这是current documentation

  • Stub :一个假的对象,只返回告诉它的内容;默认 否则为值(0,空等)。
  • 模拟:类似于存根,但它 还可以测试对对象进行的方法调用次数。
  • 间谍:对象的正常实例化,模拟被应用为拦截对象调用的侦听器。这使您可以正常使用对象,只有指定的方法行为发生变化。也可以在模拟行为期间的某个时刻调用原始代码。

我的问题...你是否试图测试prettyPrint()单独工作正常,SubjectDN.toString()打印正确,还是两者的组合?我的建议是让你的mock返回一个实际的SubjectDN()对象,然后你也可以测试它。没有更多的工作,如果出现问题,你可以更好地了解问题的起源。 Max的解决方案将解决您的问题;我没有仔细阅读或遵循良好的测试范围实践。我会把剩下的答案留作思考。如果你想将Max的stub方法与我的参数化混合,我建议将where块中的所需字符串传递给setup块中的stub创建。

这开始脱离主题,但是如果你需要测试多个SubjectDN场景(null,empty,各种大写,数字等);你也应该考虑参数化你的测试。

def "pretty print returns correct string"() {
    setup:
        X509Certificate stubCert = Mock()
        stubCert.getSubjectDN() >> subject 

    expect:
        subject.toString() == expectedToString
        X509CertificateUtils.prettyPrint(stubCert) == expectedFormatted

    where:
        subject | expectedToString | expectedFormatted
        new SubjectDN("") | ???? | "Subject: ????"
        new SubjectDN(null) | ???? | "Subject: ????"
        new SubjectDN("test") | "test" | "Subject: Test"
        new SubjectDN("testing") | "testing" | "Subject: Testing"
}

如果您的漂亮打印真的像预先“主题:”一样简单,您可能会计算出您的预期格式变量;但是你真的不应该让你的测试模仿你正在测试的代码,以便更容易进行测试。

我还发现,当迭代具有流体长度时,参数化测试的表格式会变得混乱或难以维护。我的偏好是制作一个地图列表,每个地图代表一次测试迭代。它将每个测试迭代捆绑在一起,让不熟悉的开发人员更好地了解每次迭代测试的内容。

@Unroll(iteration.testName) // Shows each iteration in its own result (in most IDEs)
def "testing printing of a SubjectDN"() {
    setup:
        X509Certificate stubCert = Mock()
        stubCert.getSubjectDN() >> iteration.subject 

    expect:
        subject.toString() == iteration.expectedToString
        X509CertificateUtils.prettyPrint(stubCert) == expectedFormatted

    where:
        iteration << [
            [testName: "Testing pretty printing a normal SubjectDN",
             subject: new SubjectDN("test"),
             expectedToString: "test"],

            [testName: "Testing pretty printing a normal SubjectDN",
             subject: new SubjectDN("testing 123"),
             expectedToString: "testing 123"],

            [testName: "Testing pretty printing a null SubjectDN",
             subject: new SubjectDN(null),
             expectedToString: ????] 

            // And so on...             
        ]

        expectedFormatted = "Subject: ${iteration.expectedToString}"
}