Статьи

Реализация тестовых коллекций с использованием Guava

В настоящее время я добавляю новую функцию в LibFX , для которой я создаю некоторые пользовательские коллекции, схожие с таковыми из Java Collections Framework . Я отправился на поиски тестов, которые мог бы выполнить против них, и был рад узнать, что Google Guava содержит именно то, что мне нужно: массивный набор тестов, который проверяет каждый уголок моей реализации для всех интерфейсов сбора из JDK и Guava.

Давайте кратко рассмотрим это.

обзор

В этом посте сначала будет показано, как настроить проект, а затем посмотреть, как начать работу с реальными тестами.

Я не создал специальных примеров, но вы можете видеть, как я использовал это в LibFX .

Настроить

Чтобы это работало, нам нужен JUnit, Guava-Testlib и небольшой шаблонный код.

Получить JUnit

Если вы еще не используете JUnit в своем проекте, загрузите его здесь . Если вы используете Maven или Gradle:

<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
	<scope>test</scope>
</dependency>
testCompile 'junit:junit:4.12'

Получить гуаву

Что нам действительно нужно, так это не сама Гуава, а Гуава-Тестлиб . Вы можете скачать его из центрального репозитория , который также содержит информацию о зависимостях для разных менеджеров.

Для вашего удобства:

<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava-testlib</artifactId>
	<version>18.0</version>
	<scope>test</scope>
</dependency>
testCompile 'com.google.guava:guava-testlib:18.0'

Напишите немного

Предположим, вы хотите написать MySet и соответствующий MySetTest .

Делая это JUnit-3.8.x-way, создайте метод publicstaticTest suite (); , JUnit ищет этот метод и использует его для определения всех тестов, которые он будет выполнять для этого класса. Внутри этого метода создайте TestSuite и добавьте тесты, которые мы собираемся записать ниже:

public class MySetTest {

	public static Test suite() {
		return new MySetTest().allTests();
	}

	public Test allTests() {
		TestSuite suite =
			new TestSuite("package.name.of.MySetTest");
		suite.addTest(testForOneToWayUseMySet());
		suite.addTest(testForAnotherWayToUseMySet());
		return suite;
	}
	
}

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

Имея этот шаблон, вы можете запускать этот класс с JUnit, например, изнутри вашей IDE или с вашего CI-сервера.

Проверьте свои реализации

Теперь, когда это сделано, мы можем начать создавать тесты для наших реализаций. Или, точнее, скажите Гуаве, как это сделать для нас. Это процесс, состоящий из двух частей: один создает генератор для элементов коллекции и тестируемый модуль, другой использует один из сборщиков тестовых наборов Guava для создания полного набора тестов, адаптированных к реализации.

Мы продолжим тестировать реализацию Set . Ниже мы увидим, для каких других интерфейсов доступны тестовые наборы.

Генератор для элементов и тестируемого устройства

Разработчик набора тестов требует, чтобы вы дали ему возможность создавать образцы элементов в коллекции и создавать экземпляры вашей коллекции. Для этого вам нужно реализовать TestSetGenerator <E> (где E — тип элементов).

Это прямо с порядком (List <E>), который является единственным методом, который может потребовать некоторого размышления. Обратите внимание, что в отличие от документации, текущая версия testlib (18.0) вызывает этот метод, даже если CollectionFeature.KNOWN_ORDER не сообщается (подробности о функциях см. Ниже). В моем случае достаточно вернуть порядок вставки.

Test Suite Builder

Теперь, когда происходит настоящее волшебство. Вы берете свой генератор сверху, передаете его правильному сборщику тестов, указываете, какие функции имеет ваша коллекция, и он создаст индивидуальный и всеобъемлющий набор тестов:

public Test testForOneToWayUseMySet() {
	return SetTestSuiteBuilder
			.using(new MySetGenerator())
			.named("one way to use MySet")
			.withFeatures(
					CollectionSize.ANY,
					CollectionFeature.ALLOWS_NULL_VALUES,
					CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION,
					CollectionFeature.SUPPORTS_ADD,
					CollectionFeature.SUPPORTS_ITERATOR_REMOVE,
					CollectionFeature.SUPPORTS_REMOVE,
			)
			.createTestSuite();
}

Характеристики

Важно указать правильные функции. Взгляните на два перечисления CollectionSize и CollectionFeatures, чтобы увидеть, какие существуют возможности для описания поведения вашей коллекции.

Обратите внимание, что созданные тесты проверяют возможности в обоих направлениях! Например, если не указывать ALLOWS_NULL_VALUES, сборщик сгенерирует тесты, которые проверяют, что добавление null в коллекцию приводит к исключению NullPointerException .

Подавляющие тесты

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

Установка и удаление

Если вам нужно выполнить код до или после каждого теста, вы можете передать его как Runnable для withSetUp или withTearDown , соответственно (оба могут быть вызваны в компоновщике).

Доступные тесты

Конечно, вы можете создавать тестовые наборы и для других интерфейсов. Первый взгляд дает следующие возможности:

Коллекции Java:

  • Коллекция
  • Итератор
  • Список
  • карта
  • NavigableMap
  • NavigableSet
  • Очередь
  • Поставил
  • SortedMap
  • SortedSet

Коллекции Гуавы:

  • BiMap
  • ListMultimap
  • Multimap
  • Multiset
  • SetMultimap
  • SortedMultiset
  • SortedSetMultimap

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

Чтобы использовать их, просто внедрите соответствующий генератор Test … и передайте его соответствующему … TestSuiteBuilder .

отражение

Мы увидели, как тестировать реализации коллекций с помощью Testlib из Guava: как включить его и JUnit в наш проект, какой шаблон нам нужен для его запуска, и обзор генератора и генератора тестовых наборов. В последнем случае происходит вся магия, поскольку она создает всесторонние тесты с учетом нашего описания нашей реализации и ее возможностей.