【问题标题】:Testing whether a list contains certain mandatory and certain optional items测试列表是否包含某些强制性和某些可选项目
【发布时间】:2020-05-26 22:17:51
【问题描述】:

我试图创建一个单元测试,以确保 list(或更一般地说,container)包含某些强制性项目,同时允许它也包含一些额外的可选项目(但同样来自预定义的选项列表)。

为了明确起见,我们假设列表:

  1. 必须包含项目foobar
  2. 可能包含项目optional
  3. 不得包含任何其他项目。

在 Java 中,使用来自 AssertJ 库的方便的 satisfiesAnyOf() 函数,此测试可以编写如下:

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class C {
    @Test
    public void t0() {
        doTest(asList("foo", "bar"));
    }

    @Test
    public void t1() {
        doTest(asList("foo", "bar", "optional"));
    }

    private static void doTest(final List<String> items) {
        assertThat(items).as("items").satisfiesAnyOf(
                it -> assertThat(it).as("XXX").containsExactlyInAnyOrder("foo", "bar"),
                it -> assertThat(it).as("YYY").containsExactlyInAnyOrder("foo", "bar", "optional"));
    }
}

此代码的问题在于它只能使用 Java 8 编译器进行编译,而 Java 9+ 编译器会通过以下方式拒绝它:

C.java:[26,63] no suitable method found for containsExactlyInAnyOrder(java.lang.String,java.lang.String)
    method org.assertj.core.api.AbstractIterableAssert.containsExactlyInAnyOrder(capture#1 of ? extends java.lang.String...) is not applicable
      (varargs mismatch; java.lang.String cannot be converted to capture#1 of ? extends java.lang.String)
    method org.assertj.core.api.ListAssert.containsExactlyInAnyOrder(capture#1 of ? extends java.lang.String...) is not applicable
      (varargs mismatch; java.lang.String cannot be converted to capture#1 of ? extends java.lang.String)
C.java:[27,63] no suitable method found for containsExactlyInAnyOrder(java.lang.String,java.lang.String,java.lang.String)
    method org.assertj.core.api.AbstractIterableAssert.containsExactlyInAnyOrder(capture#2 of ? extends java.lang.String...) is not applicable
      (varargs mismatch; java.lang.String cannot be converted to capture#2 of ? extends java.lang.String)
    method org.assertj.core.api.ListAssert.containsExactlyInAnyOrder(capture#2 of ? extends java.lang.String...) is not applicable
      (varargs mismatch; java.lang.String cannot be converted to capture#2 of ? extends java.lang.String)

通过将每个 lambda 中的 itList&lt;? extends String&gt; 显式转换为 List&lt;String&gt; 可以轻松修复客户端代码,这甚至不会更改生成的字节码:

        assertThat(items).as("items").satisfiesAnyOf(
                it -> assertThat((List<String>) it).as("XXX").containsExactlyInAnyOrder("foo", "bar"),
                it -> assertThat((List<String>) it).as("YYY").containsExactlyInAnyOrder("foo", "bar", "optional"));

查看 AssertJ API,我无法弄清楚如何在没有不安全强制转换的情况下解决上述问题。

支持 Kotlin,等效的 Kotlin 代码编译得很好(it 的类型可以指定为 MutableList&lt;out String&gt;List&lt;String&gt;) :

import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4

@RunWith(JUnit4::class)
class K {
  @Test
  fun t() {
    val items = listOf("foo", "bar", "optional")

    assertThat(items).`as`("items").satisfiesAnyOf({ assertThat(it).`as`("XXX").containsExactlyInAnyOrder("foo", "bar") },
                                                   { assertThat(it).`as`("YYY").containsExactlyInAnyOrder("foo", "bar", "optional") })
  }
}

问题:

  1. Java 8Java 9 之间的 JLS 到底发生了什么变化?您能否指出规范中禁止成功编译的确切部分?
  2. 如何重写上述 Java 代码以避免显式类型转换?

【问题讨论】:

  • 注意:最好使用(List&lt;String&gt; it) -&gt; assertThat(...,而不是强制转换。
  • @AndyTurner 确实,但这不会编译。 satisfiesAnyOf() 期望的 lambda 类型应该是 Consumer&lt;List&lt;? extends String&gt;&gt;

标签: java generics kotlin crtp assertj


【解决方案1】:

你使用的是什么版本的AssertJ

AssertJ Core 3.15.0 中使用 Java 9 解决了一个错误。如果您还没有尝试过,我会尝试使用 3.16 看看效果如何。

【讨论】:

猜你喜欢
  • 2012-05-26
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-30
  • 2011-02-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多