Micronaut:将带有 @属性 的值列表注入测试 class 无法按预期工作

Micronaut: Injecting a list of values with @Property to a test class does not work as expected

我如何定义一些特定的 属性 来测试它是一个列表而不仅仅是一个字符串?

documentation explains, how to do with string,但我无法将 value 设置为字符串列表。

application.yml

items:
  - "Item 1"
  - "Item 2"

测试文件:

@MicronautTest(environments = ["test"])
class MyTest {

    @Test
    @Property(name = "items", value = "Item 1,Item 2") // this does not work
    fun justWithOneItem() {
        // ...
    }
}

在实际代码中,这是可行的 (as documented here)

项目文件:

@Singleton
class SomeClass {
    @set:Inject
    @setparam:Property(name = "items")
    var items: List<String>? = null

    // ...
}

我知道我可以创建一个 application-test.yml 并执行

@MicronautTest(environments = ["test"])
class MyTest {
    // ...
}

但我更愿意以编程方式设置它,而不是创建新的 env/yaml 文件。

如果您在测试 class 中注入 items 列表,那么将 @Property 添加到这样的测试方法中是可行的。像这样:(我知道这是 Spock 测试,而不是 Kotlin,但你应该明白这一点。)

package com.github.wololock.micronaut.products

import io.micronaut.context.annotation.Property
import io.micronaut.test.annotation.MicronautTest
import spock.lang.Specification

@MicronautTest(environments = ["test"])
class MyTest extends Specification {

    @Property(name = "items")
    List<String> items

    def "should use default items"() {
        expect:
        items == ["Item 1", "Item 2"]
    }

    @Property(name = "items", value = "Item 3,Item 4,Item 5")
    def "should override default items"() {
        expect:
        items == ["Item 3", "Item 4", "Item 5"]
    }
}

但是,您正在使用 SomeClass 的 bean,它使用注入的项目。这里的问题是,当您将 someClass 对象注入测试 class 时,bean 已经创建并且是不可变的。这就是为什么在其中一种测试方法下添加 @Property 不会重建 bean 对象的原因。

package com.github.wololock.micronaut.products

import io.micronaut.context.annotation.Property
import io.micronaut.test.annotation.MicronautTest
import spock.lang.Specification

import javax.inject.Inject

@MicronautTest(environments = ["test"])
class MyTest extends Specification {

    @Inject
    SomeClass someClass

    def "should use default items"() {
        expect:
        someClass.items == ["Item 1", "Item 2"]
    }

    @Property(name = "items", value = "Item 3,Item 4,Item 5")
    def "should override default items"() {
        expect:
        someClass.items == ["Item 3", "Item 4", "Item 5"]
    }
}

输出:

幸运的是,这个问题有解决方案。您可以使用 @MockBean 来交付 SomeClass 对象的实现。在这种情况下,您可以定义一个需要 @Property(name="items") List<String> items 参数的方法,因此在测试方法上添加 @Property 注释将覆盖传递给使用 @MockBean:[=25= 注释的方法的值]

package com.github.wololock.micronaut.products

import io.micronaut.context.annotation.Property
import io.micronaut.test.annotation.MicronautTest
import io.micronaut.test.annotation.MockBean
import spock.lang.Specification

import javax.inject.Inject

@MicronautTest(environments = ["test"])
class MyTest extends Specification {

    @Inject
    SomeClass someClass

    def "should use default items"() {
        expect:
        someClass.items == ["Item 1", "Item 2"]
    }

    @Property(name = "items", value = "Item 3,Item 4,Item 5")
    def "should override default items"() {
        expect:
        someClass.items == ["Item 3", "Item 4", "Item 5"]
    }

    @MockBean(SomeClass)
    SomeClass someClassMock(@Property(name = "items") List<String> items) {
        return new SomeClass(items)
    }
}

输出:

我在示例中使用了 Java 和 Spock Framework 测试 (Groovy),但您应该能够使用 Kotlin 实现相同的效果。希望对你有帮助。

我想你有两个选择:

  1. 使用@Property(name = "items[0]", value = "Item1")@Property(name = "items[1]", value = "Item2")

  2. 更改测试以实现 TestPropertyProvider 并通过返回的映射提供配置