Под катом несколько полезных примеров, которые покажут положительные стороны рефлексии.
Тренироваться будем на
public interface ISort {
int[] sort(int[] ints);
}
public class MergeSort implements ISort {
// Реализация сортировки
}
public class QuickSort implements ISort {
// Реализация сортировки
}
Сразу представим себе ситуацию, что сортировок мы хотим изучить много, хотим, чтобы все они работали и были оттестированы.
Однако писать на все алгоритмы тесты нам лень. Поэтому мы протестируем только интерфейс ISort, а все остальные классы, как бы сами собой будут протестированы )
// Делаем тест в виде шаблона
public abstract class ISortTest<T extends ISort> {
private Class<T> aClass;
private T sortAlgorithm;
public ISortTest() {
// Получаем тип дженерика заданного в шаблоне
aClass = Optional.of(getClass())
.map(Class::getGenericSuperclass)
.filter(el -> el instanceof ParameterizedType)
.map( el -> (ParameterizedType) el)
.filter(el -> el.getActualTypeArguments().length > 0)
.map(el -> el.getActualTypeArguments()[0])
.filter(el -> el instanceof Class)
.map(el -> (Class<T>) el)
.orElse(null);
}
@BeforeEach
void init() throws IllegalAccessException, InstantiationException {
// Получаем экземпляр конкретной сортировки
sortAlgorithm = aClass.newInstance();
}
@Test
void sortTest() {
assertNotNull(sortAlgorithm);
int n = 10000;
int[] ints = new Random().ints().limit(n).toArray();
int[] sortInts = Arrays.stream(ints)
.sorted()
.toArray();
int[] testSotrInts = sortAlgorithm.sort(ints);
assertArrayEquals(sortInts, testSotrInts);
}
}
Ну вот и всё, теперь можно официально объявить о победе лени.
Тестирование сортировок теперь будет сведено к созданию таких вот классов
class MergeSortTest extends ISortTest<MergeSort> {
// Тут ничего нет
}
class QuickSortTest extends ISortTest<QuickSort> {
// Тут ничего нет
}
Подобный подход применяется, например, в Spring Data
public interface TestRepository extends CrudRepository<MyEntity, Long> {
}
А так же в других местах, о которых мы даже и не догадываемся.
Комментарии (18)
javaevangelist
30.03.2018 22:59А почему просто нельзя то вернуть дата провайдер с имплиментациями алгоритмов сортировок и в одном тесте их все прогнать? Еще уродливый и не эффективный стрим в конструкторе.
PqDn Автор
31.03.2018 00:53Представте, что таких классов несколько сотен
javaevangelist
31.03.2018 14:20и что? В вашем случае 100 дочерних пустых классов будет, нахер бы они нужны были? Просто мусор
aleksandy
01.04.2018 14:33Всё решается гораздо проще и без всякого наследования.
JUnit4@RunWith(Parameterized.class) public class ISortTest { private ISort sortAlgorithm; public ISortTest(ISort sortAlgorithm) { this.sortAlgorithm = sortAlgorithm; } @Test public void sort() { assertNotNull(sortAlgorithm); int n = 10000; int[] ints = new Random().ints().limit(n).toArray(); int[] sortInts = Arrays.stream(ints) .sorted() .toArray(); int[] testSotrInts = sortAlgorithm.sort(ints); assertArrayEquals(sortInts, testSotrInts); } @Parameterized.Parameters public static Collection<Object[]> data() { return Arrays.asList( new Object[] { new BubleSort() }, new Object[] { new MergeSort() } ); } }
javaevangelist
01.04.2018 14:46Дак вот! Я о том же, и без рефлексии, по крайней мере самопальной
PqDn Автор
01.04.2018 16:01Ну тут всего лишь пример, так получилось что для тестирования…
Пример показывает как использовать рефлексию для работы с дженериками.
Если брать JUnit, то там внутри очень много рефлексии.
Если взять спринг, то там очень много рефлексии.
Всё это удобно и классно
Но чтобы сделать что-то подобное самому, нужно понимать как и самому сделать такое.javaevangelist
01.04.2018 20:00Тогда надо было назвать статью «Как работать с generics через reflection api»
zagayevskiy
Даже если не говорить о полезности и правильности таких "тестов", почему бы просто не пропихнуть тестируемый инстанс через фабричный метод? Кода было бы даже меньше, и без рефлексии.
PqDn Автор
так я понимаю в этом случае придется что-то писать в наследных тестах? Правильно я вас понял?
zagayevskiy
А здесь не надо?
PqDn Автор
нет, если функционал не расширять
zagayevskiy
PqDn Автор
Я имел ввиду в теле класса ничего писать не надо
zagayevskiy
А где плюс этого-то? Что не надо писать, одну строку? Серьёзно? Унесите это с хабра и закопайте где-нибудь.
Простейший пример — в конструктор каждой конкретной реализации нужно передать некие аргументы, всегда разные. Что делать будете?
PqDn Автор
Это очень простой пример. Я всего лишь хотел показать как для таких ситуаций использовать рефлексию…
Поверьте можно оч. крутые вещи делать таким подходом
PqDn Автор
Да вы знатный троль
zagayevskiy
Эээ… Я тролль?..