Проверка наличия в списке определенных обязательных и определенных необязательных элементов - PullRequest
0 голосов
/ 27 мая 2020

Я пытался создать модульный тест, который бы удостоверился, что список (или, в более общем смысле, контейнер ) содержит определенные обязательные элементы, при этом позволяя ему также содержать некоторые дополнительные необязательные элементы (но опять же из заранее определенного списка опций).

Предположим для определенности, что список:

  1. должен содержать элементы foo и bar;
  2. может содержать элемент optional;
  3. не может содержать какие-либо другие элементы.

В Java, используя удобный satisfiesAnyOf() из библиотеки AssertJ , этот тест можно записать следующим образом:

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)

Клиентский код может быть легко исправлен путем явного преобразования it в каждой лямбде от List<? extends String> до List<String>, который даже не меняет сгенерированный байт-код:

        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 может быть указан как eith эр MutableList<out String> или List<String>):

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. Что именно изменилось в JLS между Java 8 и Java 9 ? Не могли бы вы указать мне точный раздел спецификации, запрещающий успешную компиляцию?
  2. Как можно переписать приведенный выше код Java, чтобы избежать явного приведения типов?

1 Ответ

0 голосов
/ 27 мая 2020

Какую версию AssertJ вы используете?

Исправлена ​​ошибка Java 9 в AssertJ Core 3.15.0. Я бы поставил ему go с 3.16 и посмотрел бы, как оно пойдет, если бы вы еще не пробовали.

...