Источник данных таблицы
Прежде чем переходить к этому разделу, убедитесь, что вы знакомы с базовым выполнением TAEF и знаете, как создавать тесты с его помощью.
Теперь, когда у вас есть базовая автоматизация тестирования, написанная и работающая с TAEF, вы можете сосредоточиться на сценариях, в которых один и тот же тестовый код можно использовать для работы с различными наборами данных. Для этой цели TAEF предоставляет подход на основе таблиц к тестам, управляемым данными. Давайте рассмотрим простой пример, чтобы понять, как создать тест на основе данных.
Рассмотрим простой пример, не управляемый данными, в котором вы печатаете размер и тему в консоли. В этом упражнении вы преобразуете этот тест в тест на основе данных.
1 namespace WEX { namespace TestExecution { namespace Examples
2 {
3 void DataDrivenTests::FirstTable()
4 {
5 int size = 12;
6 Log::Comment(String().Format(L"Size retrieved was %d", size));
7 }
8
9 void DataDrivenTests::SecondTable()
10 {
11 String theme = "Aero";
12 Log::Comment(L"Theme supplied as " + theme);
13 }
14 } /* namespace Examples */ } /* namespace TestExecution */ } /* namespace WEX */
Определение данных
Теперь вы хотите, чтобы приведенная выше функция работала для набора размеров и тем. Иными словами, вам нужны вариантные значения данных, которые может использовать наша функция. Для этого определите две таблицы в XML-файле DataDrivenTests.xml :
1 <?xml version="1.0"?>
2 <Data>
3 <Table Id ="Table1">
4 <ParameterTypes>
5 <ParameterType Name="Size">Int32</ParameterType>
6 <ParameterType Name="Color">String</ParameterType>
7 <ParameterType Name="Transparency">Boolean</ParameterType>
8 </ParameterTypes>
9 <Row Priority="1" Owner="C2">
10 <Parameter Name="Size">12</Parameter>
11 <Parameter Name="Color">Blue</Parameter>
12 <Parameter Name="Transparency">True</Parameter>
13 </Row>
14 <Row Priority="2" Owner="wex">
15 <Parameter Name="Size">4</Parameter>
16 <Parameter Name="Color">White</Parameter>
17 <Parameter Name="Transparency">False</Parameter>
18 </Row>
19 <Row Owner="C2">
20 <Parameter Name="Size">9</Parameter>
21 <Parameter Name="Color">Black</Parameter>
22 <Parameter Name="Transparency">True</Parameter>
23 </Row>
24 </Table>
25 <Table id ="Table2">
26 <Row Description="ButtonTest" Owner="C2" Priority="1">
27 <Parameter Name="Control">Button</Parameter>
28 <Parameter Name="Theme">Aero</Parameter>
29 </Row>
30 <Row Description="ComboBoxTest" Priority="2">
31 <Parameter Name="Control">ComboBox</Parameter>
32 <Parameter Name="Theme">Classic</Parameter>
33 </Row>
34 <Row Description="ListviewTest" Owner="wex">
35 <Parameter Name="Control">Listview</Parameter>
36 <Parameter Name="Theme">AeroBasic</Parameter>
37 </Row>
38 </Table>
39 </Data>
Теперь определены две таблицы: Table1 и Table2. В одном XML-файле можно определить таблицы для нескольких методов тестирования.
Обратите внимание, что в Таблице 1 вы заранее определили ParameterTypes и выбрали "Размер" как целое число. Раздел ParameterTypes является необязательным. По умолчанию, если сведения о типе параметра не указаны, они будут сохранены в виде строки. Это относится ко всем параметрам в "Table2".
Каждая строка, определенная в таблице, представляет собой набор значений данных (параметров), которые будет принимать функция тестирования. Строки 9, 14 и 19 определяют три набора данных, которые будет принимать наша функция FirstTable. Аналогичным образом, строки 26, 30 и 34 определяют наборы данных для SecondTable.
Обратите внимание на строки 9, 14, 19, 26, 30 и 34 в приведенном выше примере. Вы можете определить метаданные, относящиеся к строке. Теперь существует способ изменения сведений о метаданных с помощью наборов данных для той же функции. Приоритет для первого набора данных (строка 9) — 1, приоритет для второго набора данных (строка 14) — 2, а третий набор данных (строка 19) по умолчанию имеет приоритет функции. Все строки наследуют метаданные от функции, с которым связана таблица. Если те же метаданные снова заданы на уровне строк, они переопределяют значения метаданных, определенные на уровне функции.
ПРИМЕЧАНИЕ. Определение схемы XML-файла одинаково для собственного и управляемого кода, за исключением поддерживаемых определений типов. Еще один пример определения данных см. в начальной части раздела "Управляемый тест на основе данных" ниже. Перейдите к тесту на основе собственных данных, чтобы понять типы, разрешенные в машинном коде.
Собственный тест на основе данных
Теперь, когда наборы данных определены и готовы к использованию, вам потребуется способ квалифицировать тестовую функцию в качестве управляемого данными теста и связать ее с таблицей, определяющей набор данных. Это делается с помощью дополнительных метаданных при создании теста:
1 namespace WEX { namespace TestExecution { namespace Examples
2 {
3 class DataDrivenTests
4 {
5 TEST_CLASS(DataDrivenTests);
6
7 BEGIN_TEST_METHOD(SecondTable)
8 TEST_METHOD_PROPERTY(L"DataSource", L"Table:DataDrivenTests.xml#Table2")
9 TEST_METHOD_PROPERTY(L"Priority", L"3")
10 END_TEST_METHOD()
11
12 BEGIN_TEST_METHOD(FirstTable)
13 TEST_METHOD_PROPERTY(L"Priority", L"4")
14 TEST_METHOD_PROPERTY(L"DataSource", L"Table:DataDrivenTests.xml#Table1")
15 END_TEST_METHOD()
16 };
17 } /* namespace Examples */ } /* namespace TestExecution */ } /* namespace WEX */
Чтобы связать XML-таблицу с тестом, добавьте метаданные DataSource в метод теста. Благодаря этой связи TAEF будет использовать заданный DataSource для запуска теста. Значение DataSource состоит из трех частей:
- "Table:" — определяет источник данных как XML-таблицу.
- "DataDrivenTests.xml" — это файл, содержащий XML-таблицу.
- "#Table2" — после делиметра "#" значение "Table2" определяет конкретную таблицу в XML-документе для использования. Один источник данных таблицы XML может содержать несколько таблиц. TAEF будет просматривать XML-файл для элемента Table с атрибутом Id, соответствующим указанному значению.
В приведенном выше примере вы могли заметить, что "SecondTable" определена перед "FirstTable". Это означает, что функция SecondTable будет выполняться до функции FirstTable, но вы определили "Table1", соответствующую "FirstTable", перед "Table2", таблицу, соответствующую "SecondTable". Это делается для того, чтобы подчеркнуть, что порядок определения таблицы не имеет значения при обнаружении и выполнении тестов, управляемых данными.
После завершения сопоставления источника данных с методом тестирования вы можете изменить пример, чтобы получить данные из источника. Перед этим ознакомьтесь с опубликованным файлом заголовка TestData.h. Интересная часть:
1 class TestData
2 {
3 public:
4 template <typename T>
5 static HRESULT __stdcall TryGetValue(_In_z_ const wchar_t* pszString, T& result)
6 {
7 return Private::TestData<T>::TryGetValue(pszString, result);
8 }
9 };
В строке 5 показан API для вызова для получения данных в функции. Ознакомьтесь с доступными типами параметров для получения.
Ок . Все настроено для повторной записи нашего примера:
1 namespace WEX { namespace TestExecution { namespace Examples
2 {
3 void DataDrivenTests::FirstTable()
4 {
5 Log::Comment(L"I am in first table");
6 int size;
7 if (SUCCEEDED(TestData::TryGetValue(L"size", size)))
8 {
9 VERIFY_ARE_NOT_EQUAL(size, 0);
10 Log::Comment(String().Format(L"Size retrieved was %d", size));
11 }
12 }
13
14 void DataDrivenTests::SecondTable()
15 {
16 Log::Comment(L"I am in second table.");
17 String theme;
18 if (SUCCEEDED(TestData::TryGetValue(L"theme", theme)))
19 {
20 Log::Comment(L"Theme supplied as " + theme);
21 }
22 }
23 } /* namespace Examples */ } /* namespace TestExecution */ } /* namespace WEX */
Строки 7 и 18 — это main части, которые были изменены, чтобы сделать тестовые данные управляемыми. Не очень много изменений. Ознакомьтесь с статьей Выполнение управляемых данными тестов, чтобы понять, как максимально эффективно использовать TAEF при выполнении тестов на основе данных.
Управляемый тест на основе данных
Рассмотрим пример, в котором требуется распечатать координаты прямоугольника на консоли. Начните с определения этих координат в виде набора данных в XML-файле.
1 <?xml version="1.0"?>
2 <Data>
3 <Table Id="FirstTable">
4 <ParameterTypes>
5 <ParameterType Name="Left">Int32</ParameterType>
6 <ParameterType Name="Right">String</ParameterType>
7 <ParameterType Name="Top">Integer</ParameterType>
8 <ParameterType Name="Bottom">Int32</ParameterType>
9 </ParameterTypes>
10 <Row Priority="1" Owner="C2" Description="Zero rect">
11 <Parameter Name="Left">0</Parameter>
12 <Parameter Name="Right">0</Parameter>
13 <Parameter Name="Top">0</Parameter>
14 <Parameter Name="Bottom">0</Parameter>
15 </Row>
16 <Row Priority="2" Owner="wex" Description="normal rect">
17 <Parameter Name="Left">12</Parameter>
18 <Parameter Name="Right">25</Parameter>
19 <Parameter Name="Top">10</Parameter>
20 <Parameter Name="Bottom">50</Parameter>
21 </Row>
22 <Row Owner="C2" Description="invalid rect">
23 <Parameter Name="Left">30</Parameter>
24 <Parameter Name="Right">15</Parameter>
25 <Parameter Name="Top">40</Parameter>
26 <Parameter Name="Bottom">10</Parameter>
27 </Row>
28 </Table>
29 </Data>
Определите набор данных в область таблицы, в данном случае FirstTable, которая определена в строке 3 выше. В одном XML-файле можно определить таблицы для нескольких методов тестирования.
Обратите внимание, что FirstTable заранее определяет ParameterTypes и вызывает "Left" как Int32. Раздел ParameterTypes является необязательным. По умолчанию, если сведения о типе параметра не указаны, они будут сохранены в виде строки.
Ознакомьтесь со списком поддерживаемых типов параметров.
Если указан какой-либо другой тип данных, тест выдаст предупреждение и сочтет его строкой.
ПРИМЕЧАНИЕ. Строки типа не учитывают регистр, но должны орфографироваться точно так, как показано выше.
Каждая строка, определенная в таблице, представляет собой набор значений данных (параметров), которые требуется принять тестовой функцией. Строки 10, 16 и 22 определяют три набора данных, которые наша функция.
Обратите внимание на строки 10, 16 и 22 в приведенном выше примере. Вы можете определить метаданные, относящиеся к строке. Теперь у вас есть способ изменения сведений о метаданных с помощью наборов данных для той же функции. Приоритет для первого набора данных (строка 10) — 1, приоритет для второго набора данных (строка 16) — 2, а третий набор данных (строка 22) по умолчанию имеет приоритет функции. Все строки наследуют метаданные от функции, с которым связана таблица. Если те же метаданные снова заданы на уровне строк, они переопределяют значения метаданных, определенные на уровне функции.
ПРИМЕЧАНИЕ. Определение схемы XML-файла одинаково для собственного и управляемого кода, за исключением поддерживаемых определений типов. Еще один пример определения см. в разделе "Определение данных" в верхней части этой страницы.
Теперь все данные определены. В следующем примере показано, как получить к нему доступ.
1 namespace WEX.Examples
2 {
3 using Microsoft.VisualStudio.TestTools.UnitTesting;
4 using System;
5 using System.Collections;
6 using WEX.Logging.Interop;
7 using WEX.TestExecution;
8
9 [TestClass]
10 public class CSharpDataDrivenTests
11 {
12 [TestMethod]
15 [DataSource("Table:CSharpDataDrivenTests.xml#FirstTable")]
16 public void First()
17 {
18 Console.WriteLine("Left is " + m_testContext.DataRow["Left"].ToString());
19
20 Log.Comment("In CSharpDataDrivenTests.First");
21 }
22
23 [TestMethod]
24 public void Second()
25 {
26 Log.Comment("In CSharpDataDrivenTests.Second");
27 Verify.IsTrue(true);
28 }
29
30 public TestContext TestContext
31 {
32 get { return m_testContext; }
33 set { m_testContext = value; }
34 }
35
36 private TestContext m_testContext;
37 }
38 }
Связывание XML-таблицы с заданным методом теста в управляемом коде очень похоже на машинный код; просто примените метаданные DataSource. Как и раньше, он состоит из трех частей:
- "Table:", чтобы определить источник данных как XML-таблицу.
- "CSharpDataDrivenTests.xml" — файл, содержащий XML-таблицу.
- "#FirstTable" — после делиметра "#" значение FirstTable определяет конкретную таблицу в XML-документе для использования. TAEF будет просматривать XML-файл для элемента Table с атрибутом Id, соответствующим указанному значению.
Обратите внимание, что функция Second не управляется данными. Вы можете использовать только некоторые тесты для управления данными. Кроме того, у каждого теста есть возможность определить таблицу в другом XML-файле.
В строке 36 определяется частное свойство TestContext, например VSTS рекомендует класс TestContext. Вы также определяете открытые оценщики для этого свойства (строки с 30 по 34). Внутренне TAEF загружает свойство словаря TestContext с соответствующим набором данных в фокусе.
TestContext определяется в Microsoft.VisualStudio.TestTools.UnitTesting. См. строку 3 в приведенном выше примере. Вы уже должны включать его в качестве ссылки в разработку управляемых тестов. Таким образом, дополнительные ссылки не требуются для разработки тестов на основе данных.
В строке 18 приведенного выше примера показано, как получить данные в функции . Обратите внимание, что данные доступны в m_testContext.DataRow.
Имя вместо индекса для идентификации объекта DataRow
TAEF позволяет использовать более понятное свойство Name вместо Index для идентификации любого объекта DataRow в источнике данных. Для этого просто добавьте метаданные Name на уровне строки в источнике данных. Наш первый пример на этой странице можно изменить для использования этой функции следующим образом:
1 <?xml version="1.0"?>
2 <Data>
3 <Table id ="Table1">
4 <ParameterTypes>
5 <ParameterType Name="Size">Int32</ParameterType>
6 <ParameterType Name="Color">String</ParameterType>
7 <ParameterType Name="Transparency">Boolean</ParameterType>
8 </ParameterTypes>
9 <Row Name='BlueTransparent' Priority="1" Owner="C2">
10 <Parameter Name="Size">12</Parameter>
11 <Parameter Name="Color">Blue</Parameter>
12 <Parameter Name="Transparency">True</Parameter>
13 </Row>
14 <Row Priority="2" Owner="wex">
15 <Parameter Name="Size">4</Parameter>
16 <Parameter Name="Color">White</Parameter>
17 <Parameter Name="Transparency">False</Parameter>
18 </Row>
19 <Row Name='BlackTransparent' Owner="C2">
20 <Parameter Name="Size">9</Parameter>
21 <Parameter Name="Color">Black</Parameter>
22 <Parameter Name="Transparency">True</Parameter>
23 </Row>
24 </Table>
25 ...
39 </Data>
В приведенном выше измененном примере BlueTransparent соответствует индексу 0. Строка с индексом 1 не имеет специального имени, а строка с индексом 2 связана с именем BlackTransparent. Вы по-прежнему можете использовать запрос выбора для поиска индекса 0 или 2 в "Table1", и он найдет правильную строку. Но при выполнении или перечислении библиотеки DLL вместо просмотра:
<qualified name of the test method>#<index>
Вместо этого вы увидите:
<qualified name of the test method>#<name property provided at Row level>
для строк, где атрибут Name предоставляется на уровне строки. Если свойство "Name" не указано ни для одной строки, как в случае с индексом 1 выше, по умолчанию используется #<index> по полному имени метода.
Обратите внимание, что путем предоставления атрибута "Name" на уровне строки вы существенно изменяете способ, которым TAEF интерпретирует имя экземпляра вызова метода с соответствующими данными Row.
DataSource в качестве параметра среды выполнения
TAEF поддерживает предоставление источника данных в качестве параметра среды выполнения. Для этого используйте следующий синтаксис.
te <test dll names> /p:<DataSource runtime name>=Table:<DataSoure XML file>#<Table Id>
При создании теста необходимо указать "p:<DataSource runtime name>" в качестве источника данных. Помните, что во время выполнения необходимо указать полную строку — имя XML-файла, а также идентификатор таблицы. TableId не должен предоставляться в качестве тестовых метаданных, если источник данных предоставляется во время выполнения. Префикс "Table:" указывает, что вы ищете источник данных таблицы.
Вы можете попробовать это с помощью одного из примеров, доступных в общей папке выпуска:
te Examples\CPP.RuntimeDataSource.Example.dll /p:MyDataSource=Table:RuntimeDataSourceExample.xml#SimpleTable
DataSource как ресурс
TAEF позволяет добавить DataSource в качестве ресурса тестового модуля при условии, что он соответствует следующим требованиям:
В случае с собственными тест-модулями это можно сделать, указав DataSource в качестве идентификатора ресурса или имени ресурса. Пример кода:
BEGIN_TEST_METHOD(ResourceNameDataSource)
TEST_METHOD_PROPERTY(L"DataSource", L"Table:MyResourceName#SimpleTable")
END_TEST_METHOD()
MyResourceName — это имя ресурса, определенное в файле ResourceDataSource.rc в данном случае:
MyResourceName DATASOURCE_XML "ResourceDataSource.xml"
В случае управляемых тестовых модулей ресурс можно указать только определенным образом, как показано в фрагменте файла источников , показанном ниже:
LANGUAGE_NEUTRAL_MANAGED_RESOURCES = CSharpAdvancedDataDrivenTests.xml
Спецификация метаданных DataSource останется той же, что и в случае указания XML-файла DataSource. Как и в случае с управляемым кодом, можно сделать имя ресурса таким же, как и имя XML-файла. Поэтому важно понимать, что TAEF сначала ищет наличие фактического файла с именем DataSource. Если такой XML-файл не найден, он будет продолжать поиск тестового ресурса в тестовом модуле с заданным именем или идентификатором ресурса. Так как указание DataSource в качестве ресурса требует повторной компиляции, вы можете воспользоваться преимуществами этой структуры, скопировав XML-файл DataSource в то же расположение, что и тестовая библиотека DLL во время разработки (и присвоив имя ресурса таким же, как имя XML-файла). Завершив тестирование, скопируйте XML обратно в каталог кода и повторно скомпилируйте как ресурс. Не забудьте удалить XML-файл из каталога выполнения. :)
Примеры пошагов
Чтобы понять различные аспекты тестирования на основе таблиц на основе данных, ознакомьтесь с некоторыми дополнительными примерами пошагов: