Создание входных данных с помощью динамического символического выполнения

IntelliTest создает входные данные для параметризованных модульных тестов путем анализа условий ветви в программе. Тестовые входные данные выбираются на основе того, могут ли они активировать новые поведения ветвления программы. Такой анализ является последовательным. Он уточняет предикат q: I -> {true, false} по формальным входным параметрам теста I. q представляет набор поведений, которые инструмент IntelliTest уже наблюдал. Изначально q := false, так как пока ничего не наблюдалось.

Ниже указаны этапы цикла:

  1. IntelliTest определяет входные параметры i так, чтобы q(i)=false, используя поиск решения для ограничения. По своему назначению входной параметр i примет путь выполнения, который не обрабатывался раньше. На начальном этапе это означает, что i может быть любым входным параметром, так как ни один путь выполнения еще не был обнаружен.

  2. IntelliTest выполняет тест с выбранным входным параметром i и отслеживает выполнение теста и тестируемую программу.

  3. Во время выполнения программа принимает определенный путь, определяемый всеми условными ветвями программы. Набор всех условий, определяющих выполнение, называется условием пути и записывается в виде предиката p: I -> {true, false} по формальным входным параметрам. IntelliTest вычисляет представление этого предиката.

  4. Инструмент IntelliTest задает q := (q or p). Другими словами, он записывает факт того, что видел путь, представленный p.

  5. Перейдите к шагу 1.

Поиск решения для ограничений в IntelliTest поддерживает значения всех типов, которые могут присутствовать в программах .NET:

IntelliTest отфильтровывает входные параметры, нарушающие заданные предположения.

Кроме непосредственных входных параметров (аргументы для параметризованных модульных тестов), тест может получать дополнительные входные значения из статического класса PexChoose. Выбор также определяют поведением параметризованных макетов.

Поиск решения для ограничений

IntelliTest использует поиск решения для ограничений, чтобы определить релевантные входные значения для теста и тестируемой программы.

В IntelliTest используется поиск решения для ограничений Z3.

Динамический объем протестированного кода

В качестве побочного эффекта мониторинга среды выполнения IntelliTest собирает данные о динамическом объеме протестированного кода. Это явление называется динамическим, так как IntelliTest известно только то, что код был выполнен, поэтому инструмент не может предоставить абсолютные значения по объему протестированного кода, как это обычно делают другие подобные средства.

Например, когда IntelliTest сообщает о динамическом объеме протестированного кода в 5–10 базовых блоках, это означает, что было протестировано пять блоков из десяти, при этом общее количество блоков во всех методах, охваченных анализом к настоящему времени (в отличие от всех методов в тестируемой сборке), равно 10. На более позднем этапе анализа по мере обнаружения дополнительных доступных методов как числитель (5 в этом примере), так и знаменатель (10) могут увеличиться.

Целые числа и числа с плавающей запятой

Поиск решения для ограничений в IntelliTest определяет тестовые входные значения типов примитивов, таких как byte, int, float и другие, чтобы активировать разные пути выполнения для теста и тестируемой программы.

Объект

IntelliTest может создавать экземпляры существующих классов .NET, либо вы можете использовать IntelliTest, чтобы автоматически создавать макеты объектов, реализующие определенный интерфейс и ведущие себя по-разному в зависимости от способа использования.

Создание экземпляров существующих классов

В чем тут дело?

IntelliTest отслеживает выполняемые инструкции, когда выполняет тест и тестируемую программу. В частности, он отслеживает любой доступ к полям. Затем этот инструмент использует поиск решения для ограничений, чтобы определить новые входные данные теста, включая объекты и их значения полей, так, что тест и тестируемая программа будут вести себя другим, нужным специалисту, образом.

Это означает, что IntelliTest должен создавать объекты определенных типов и задавать их значения полей. Если класс является видимым и имеет видимым конструктор по умолчанию, IntelliTest может создать экземпляр этого класса. Если все поля класса являются видимыми, IntelliTest может задать поля автоматически.

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

Visibility

Платформа .NET имеет тщательно проработанную модель видимости: типы, методы, поля и другие элементы могут быть закрытыми, открытыми, внутренними и иными.

Когда IntelliTest создает тесты, он пытается выполнять только действия (такие как вызов конструкторов, методов и задание полей), допустимые по отношению к правилам видимости .NET в контексте созданных тестов.

Действуют следующие правила:

  • Видимость внутренних элементов

    • IntelliTest предполагает, что созданные тесты получат доступ к внутренним элементам, которые были видны заключающему PexClass. .NET располагает InternalsVisibleToAttribute, позволяющим расширить видимость внутренних элементов на другие сборки.
  • Видимость закрытых и семейных (защищенных в C#) элементов класса PexClass

    • IntelliTest всегда помещает созданные тесты непосредственно в PexClass либо в подкласс. Таким образом, IntelliTest предполагает, что может использовать все видимые семейные элементы (защищенные в C#).
    • Если созданные тесты помещаются непосредственно в PexClass (обычно с использованием разделяемых классов), IntelliTest предполагает, что они также могут использовать все закрытые элементы PexClass.
  • Видимость открытых элементов

    • IntelliTest предполагает, что может использовать все экспортированные элементы, видимые в контексте PexClass.

Параметризованные макеты

Как протестировать метод, имеющий параметр типа интерфейса? Или незапечатанный класс? IntelliTest не знает, какие реализации будут использоваться позднее при вызове этого метода. Фактическая реализация во время тестирования может просто отсутствовать.

В общем случае рекомендуется использовать макеты объектов с явным поведением.

Макет объекта реализует интерфейс (или расширяет незапечатанный класс). Он не представляет фактическую реализацию, а является просто ярлыком, обеспечивающим выполнение тестов с помощью макета объекта. Такое поведение определяется вручную в рамках каждого тестового случая, где оно применяется. Существует множество инструментов, которые позволяют легко определить макеты объектов и их ожидаемое поведение, однако подобное поведение нужно по-прежнему задавать вручную.

Вместо использования жестко заданных значений в макетах объектов IntelliTest может самостоятельно создавать такие значения. IntelliTest также позволяет использовать параметризованные макеты по аналогии с параметризованным модульным тестированием.

Параметризованные макеты имеют два режима выполнения:

  • Выбор: при анализе кода параметризованные макеты являются источником дополнительных входных данных теста, и IntelliTest попытается выбрать нужные значения.
  • Воспроизведение: при выполнении ранее созданного теста параметризованные макеты выполняют роль заглушек с поведением (другими словами, предопределенного поведения).

Используйте PexChoose, чтобы получить значения для параметризованных макетов.

Структуры

IntelliTest работает со значениями структур точно так же, как и с объектами.

Массивы и строки

IntelliTest отслеживает выполняемые инструкции, когда выполняет тест и тестируемую программу. В частности, он обнаруживает ситуации, когда программа зависит от длины строки или массива (и нижних границ и длин многомерного массива). Он также отслеживает, как программа использует различные элементы строки или массива. Затем этот инструмент использует поиск решения для ограничений, чтобы определить, какие длины и значения элементов заставляют тест и тестируемую программу вести себя нужным специалисту образом.

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

Получение дополнительных входных данных

Статический класс PexChoose можно использовать, чтобы получить дополнительные входные данные для теста и реализовать параметризованные макеты.

Хотите отправить отзыв?

Делитесь своими идеями и пожеланиями относительно новых функций в сообществе разработчиков.