Протестируйте все перечисления, реализующие интерфейс маркера

У меня пустой интерфейс interface HavingUniqueValues(val v: Int) {} и некоторые перечисления, как enum class EnumName(override val v: Int) : HavingUniqueValues,

Я хочу, чтобы элементы в каждом перечислении были уникальными v-значения, но я могу неправильно набирать значения. Поэтому мне нужен тест.

  1. Можно ли создать тест, в котором реализации интерфейса сохраняются как List вручную и тест проверяет, все ли реализации в List соответствовать требованию?
  2. Если да: возможно ли создать функцию, которая возвращает List из всех реализаций в указанном пакете, чтобы использовать его в тесте?

2 ответа

Решение

Взгляните на библиотеку Reflections, которая может вам в этом помочь.

Вы должны быть в состоянии получить все подтипы HavingUniqueValues:

val subjects: Set<Class<out HavingUniqueValues>> =
        Reflections("your.package").getSubTypesOf(HavingUniqueValues::class.java)

Теперь это приведет к набору всех перечисляемых классов, которые реализуют HavingUniqueValues, Вы можете перебрать все их значения, чтобы узнать, являются ли они уникальными или нет:

subjects.forEach { enumClass ->
    assertEquals(
            enumClass.enumConstants.size,
            enumClass.enumConstants.map(HavingUniqueValues::v).toSet().size
    )
}

я использовал toSet() здесь, чтобы отбросить все неинекционные значения.

Это пройдет тест:

enum class EnumName(override val v: Int) : HavingUniqueValues { ONE(1), TWO(2), THREE(3) }

Это не пройдет тест:

enum class EnumName(override val v: Int) : HavingUniqueValues { ONE(1), TWO(2), THREE(2) }

Я попробовал принятое решение, и оно не сработало с перечислениями. Кажется, что библиотека Reflectons не поддерживает поиск реализаций, которые являются настраиваемыми перечислениями, исключениями и т. Д. По крайней мере, с конфигурацией по умолчанию, указанной в приведенном выше ответе. Есть много ссылок и документации, которые объясняют, почему это не сработает:

Почему Reflection.getSubTypesOf(Object.class) не находит перечисления?

https://github.com/ronmamo/reflections/issues/126

Мне удалось найти и протестировать подобное решение с помощью Classgraph

Вот пример кода, который работал у меня с перечислениями:

try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("package.with.your.enums").scan()) {
    ClassInfoList implementationsRefs = scanResult.getClassesImplementing("package.with.your.enums.yourInterfaceForEnums");
    List<Class<?>> implementations = implementationsRefs.loadClasses();
    //here goes your code that operates on "implementations"
}

Поскольку вы отметили свой вопрос kotlintestЯ превратил отличный ответ @egor в фрагмент кода KotlinTest для вас.

class MyTest : StringSpec({

  "unique values" {

    val subjects: Set<Class<out HavingUniqueValues>> =
        Reflections("your.package").getSubTypesOf(HavingUniqueValues::class.java)

    subjects.forEach { enumClass ->
      enumClass.enumConstants.size shouldBe
          enumClass.enumConstants.map(HavingUniqueValues::v).toSet().size
    }
  }

})
Другие вопросы по тегам