使用Spock第2部分测试Kotlin –使用实例方法枚举

Kotlin中带有实例方法的enum类与它的Java版本非常相似,但是它们的字节码看起来有些不同。 让我们通过使用编写一些测试来了解差异
Spock

我们要测试什么?

让我们看一下我们要测试的代码:

enum class EnumWithInstanceMethod {
    PLUS {
        override fun sign(): String = "+"
    },
    MINUS {
        override fun sign(): String = "-"
    };

    abstract fun sign(): String
}

显然,可以用更好的方式编写它(例如,使用enum实例变量),但是此示例显示了我们要以最简单的方式进行测试的情况。

如何用Spock进行测试?

最简单的测试(不起作用)

首先,我们可以像使用Java枚举一样编写测试:

def "should use enum method like in java"() {
    expect:
        EnumWithInstanceMethod.MINUS.sign() == '-'
}

测试失败:

Condition failed with Exception:

EnumWithInstanceMethod.MINUS.sign() == '-'
                             |
                             groovy.lang.MissingMethodException: No signature of method: static com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS.sign() is applicable for argument types: () values: []
                             Possible solutions: sign(), sign(), is(java.lang.Object), find(), with(groovy.lang.Closure), find(groovy.lang.Closure)


    at com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethodTest.should use enum method like in java(EnumWithInstanceMethodTest.groovy:11)
Caused by: groovy.lang.MissingMethodException: No signature of method: static com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS.sign() is applicable for argument types: () values: []
Possible solutions: sign(), sign(), is(java.lang.Object), find(), with(groovy.lang.Closure), find(groovy.lang.Closure)
    ... 1 more

有趣的是……为什么Groovy告诉我们我们正在尝试调用静态方法? 也许我们不使用枚举实例,而是其他东西? 让我们创建一个测试,将枚举实例传递给方法:

static String consume(EnumWithInstanceMethod e) {
    return e.sign()
}

def "should pass enum as parameter"() {
    expect:
        consume(EnumWithInstanceMethod.MINUS) == '-'
}

错误信息:

Condition failed with Exception:

consume(EnumWithInstanceMethod.MINUS) == '-'
|
groovy.lang.MissingMethodException: No signature of method: static com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethodTest.consume() is applicable for argument types: (java.lang.Class) values: [class com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS]
Possible solutions: consume(com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod)


    at com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethodTest.should pass enum as parameter(EnumWithInstanceMethodTest.groovy:29)
Caused by: groovy.lang.MissingMethodException: No signature of method: static com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethodTest.consume() is applicable for argument types: (java.lang.Class) values: [class com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS]
Possible solutions: consume(com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod)
    ... 1 more

现在我们看到我们通过了课程
com.github.alien11689.testingkotlinwithspock.EnumWithInstanceMethod$MINUS ,而不是枚举实例。

但是它可以在Java中工作...

JUnit中的类似代码可以完美运行,并且测试通过:

@Test
public void shouldReturnSign() {
    assertEquals("-", EnumWithInstanceMethod.MINUS.sign());
}

Java可以毫无问题地访问Kotlin的实例方法,因此Groovy可能出了点问题…

但是带有实例方法的Java枚举,例如

public enum EnumWithInstanceMethodInJava {
    PLUS {
        public String sign() {
            return "+";
        }
    },
    MINUS {
        public String sign() {
            return "-";
        }
    };

    public abstract String sign();
}

在Spock测试中可以正常工作:

def "should use enum method"() {
    expect:
        EnumWithInstanceMethodInJava.MINUS.sign() == '-'
}

有什么不同?

我们可以通过查看已编译的类来发现差异:

$ tree build/classes/main/
build/classes/main/
└── com
    └── github
        └── alien11689
            └── testingkotlinwithspock
                ├── AdultValidator.class
                ├── EnumWithInstanceMethod.class
                ├── EnumWithInstanceMethodInJava$1.class
                ├── EnumWithInstanceMethodInJava$2.class
                ├── EnumWithInstanceMethodInJava.class
                ├── EnumWithInstanceMethod$MINUS.class
                ├── EnumWithInstanceMethod$PLUS.class
                ├── Error.class
                ├── Ok.class
                ├── ValidationStatus.class
                └── Validator.class

Java生成匿名类(
EnumWithInstanceMethodInJava$1
EnumWithInstanceMethodInJava$2 ),但Kotlin用这些枚举实例名称( EnumWithInstanceMethod$MINUSEnumWithInstanceMethod$PLUS )。

它如何与Groovy相关联? Groovy不需要
.class在访问代码中的类时,因此当我们尝试访问时
EnumWithInstanceMethod.MINUS ,Groovy将其转换为 EnumWithInstanceMethod.MINUS.class ,而不是枚举的实例。 在Java代码中不会发生相同的问题,因为没有 EnumWithInstanceMethodInJava$MINUS类。

知道了差异,我们可以解决在Groovy代码中访问Kotlin的枚举实例的问题。

第一个解决方案是使用以下方法访问枚举实例
valueOf方法:

def "should use enum method working"() {
    expect:
        EnumWithInstanceMethod.valueOf('MINUS').sign() == '-'
}

第二种方法是明确告诉Groovy我们要访问作为枚举实例的静态字段:

def "should use enum method"() {
    expect:
        EnumWithInstanceMethod.@MINUS.sign() == '-'
}

您可以根据代码样式和首选项选择任何一种解决方案。

给我看代码

代码可在此处获得

翻译自: https://www.javacodegeeks.com/2018/05/testing-kotlin-spock-enum-instance-method.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值