如何使用 spock "where" table 测试重载方法

How to test overloaded method using spock "where" table

我想测试将 null 传递给这些重载方法:

public static Object someMethod(String n) { /* some impl */ }
public static Object someMethod(Integer n) { /* some impl */ }

我试过了:

def "test someMethod"() {
    expect:
    someMethod(input) == expected
    where:
    input           | expected
    null as String  | someValue
    null as Integer | someValue
}

但我收到错误消息:

groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method com.foo.MyClass#someMethod.
Cannot resolve which method to invoke for [null] due to overlapping prototypes between:  
    [class java.lang.String]  
    [class java.lang.Integer]

如何使用一种 spock 方法在 where 块(具有其他值)中输入空值来测试这些?

我试图用 Spock 1.3 和 Groovy 2.5.8 重现您的问题,但没成功。相反,我遇到了另一个 Spock 问题,请参阅 here。您必须使用其他版本的 Spock and/or Groovy.

无论如何,我刚刚链接到的 Spock bug 的一个解决方法是不从 then:expect: 块调用带有空参数的方法,而是从 when: 和稍后在 then: 块中进行比较。另请参阅我的代码示例。

除此之外,您需要将特征方法拆分为两种方法,一种用于您要测试的每种类型的 null 对象。

Java class 测试中:

package de.scrum_master.Whosebug.q58279620;

public class ClassUnderTest {
  public static Object someMethod(String n) {
    return n == null ? "nothing" : "something";
  }

  public static Object someMethod(Integer n) {
    return n == null ? -999 : 11;
  }
}

Spock 测试解决方法:

package de.scrum_master.Whosebug.q58279620


import spock.lang.Specification
import spock.lang.Unroll

class PassingNullToOverloadedMethodTest extends Specification {
  @Unroll
  def "someMethod('#input') returns #expected"() {
    when:
    def result = ClassUnderTest.someMethod(input as String)

    then:
    result == expected

    where:
    input | expected
    "foo" | "something"
    ""    | "something"
    null  | "nothing"
  }

  @Unroll
  def "someMethod(#input) returns #expected"() {
    when:
    def result = ClassUnderTest.someMethod(input as Integer)

    then:
    result == expected

    where:
    input | expected
    0     | 11
    123   | 11
    null  | -999
  }
}

在这种情况下,类型转换不会被继承,也不能被 Spock 继承。 但是您可以手动使用 PojoWrapper,这就是 Groovy 在内部表示 type-casted null:

的方式
import org.codehaus.groovy.runtime.wrappers.PojoWrapper

def "test someMethod"() {
    expect:
    someMethod(input) == expected
    where:
    input                          | expected
    new PojoWrapper(null, String)  | someValue
    new PojoWrapper(null, Integer) | someValue
}

但有一个重要提示,第一组输入必须包含包装器,否则 Groovy 以不解包参数的方式优化 someMethod 调用。

所以这会起作用:

import org.codehaus.groovy.runtime.wrappers.PojoWrapper

def "test someMethod"() {
    expect:
    someMethod(input) == expected
    where:
    input                          | expected
    new PojoWrapper(null, Integer) | someValue
    0                              | someValue
}

虽然这行不通,但抛出 ClassCastException:

import org.codehaus.groovy.runtime.wrappers.PojoWrapper

def "test someMethod"() {
    expect:
    someMethod(input) == expected
    where:
    input                          | expected
    0                              | someValue
    new PojoWrapper(null, Integer) | someValue
}