다음을 통해 공유


테이블 데이터 원본

이 섹션을 진행하기 전에 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 파일에서 여러 테스트 메서드에 대한 테이블을 정의할 수 있습니다.

Table1에서 ParameterTypes를 앞에 정의하고 "Size"를 정수로 선택했습니다. ParameterTypes 섹션은 선택 사항입니다. 기본적으로 매개 변수 형식 정보가 제공되지 않으면 문자열로 저장됩니다. "Table2"의 모든 매개 변수에 대한 경우입니다.

테이블 내에 정의된 각 "행"은 테스트 함수가 수락할 데이터(매개 변수) 값 집합입니다. 줄 9, 14 및 19는 FirstTable 함수가 허용하는 3개의 데이터 집합을 정의합니다. 마찬가지로 줄 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 값에는 다음과 같은 세 부분이 있습니다.

  1. 'Table:' - 데이터 원본을 XML 테이블로 식별합니다.
  2. 'DataDrivenTests.xml' - XML 테이블이 포함된 파일입니다.
  3. '#Table2' - '#' 구분 기호에 따라 'Table2' 값은 사용할 XML 문서 내의 특정 테이블을 식별합니다. 단일 XML 테이블 데이터 원본에는 여러 테이블이 포함될 수 있습니다. TAEF는 지정된 값과 일치하는 'Id' 특성이 있는 Table 요소에 대한 XML 파일을 살펴봅니다.

위의 예제에서 "SecondTable"이 "FirstTable" 앞에 정의되어 있음을 관찰했을 수 있습니다. 즉, "SecondTable" 함수는 "FirstTable" 함수 이전에 실행되지만 "Table1"은 "SecondTable"에 해당하는 테이블인 "Table2" 앞에 "FirstTable"에 해당하는 테이블을 정의했습니다. 이는 데이터 기반 테스트를 검색하고 실행하는 동안 테이블 정의의 순서가 무관하다는 점을 강조하기 위한 것입니다.

데이터 원본을 테스트 메서드에 매핑하면 이제 예제를 수정하여 원본에서 데이터를 가져올 수 있습니다. 이렇게 하기 전에 게시된 헤더 파일 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줄은 테스트 데이터를 구동하기 위해 변경된 기본 부분입니다. 큰 변화는 아닙니다. 데이터 기반 테스트를 실행하는 동안 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>

테이블의 scope 데이터 집합을 정의합니다. 이 경우 위의 3줄에 정의된 "FirstTable"입니다. 동일한 XML 파일에서 여러 테스트 메서드에 대한 테이블을 정의할 수 있습니다.

FirstTable이 ParameterTypes를 미리 정의하고 "Left"를 "Int32"로 호출하는지 확인합니다. ParameterTypes 섹션은 선택 사항입니다. 기본적으로 매개 변수 형식 정보가 제공되지 않으면 문자열로 저장됩니다.

지원되는 매개 변수 형식 목록을 살펴보세요.

다른 데이터 형식이 지정된 경우 테스트는 경고를 throw하고 문자열로 간주합니다.

참고: 형식 문자열은 대/소문자를 구분하지 않지만 위에 표시된 대로 정확하게 철자가 지정되어야 합니다.

테이블 내에 정의된 각 "행"은 테스트 함수가 수락할 데이터(매개 변수) 값 집합입니다. 줄 10, 16 및 22는 함수가 작동하는 3개의 데이터 집합을 정의합니다.

위의 예제에서 줄 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' 메타데이터를 적용하기만 하면됩니다. 이전과 마찬가지로 다음 세 부분으로 구성됩니다.

  1. 'Table:' - 데이터 원본을 XML 테이블로 식별합니다.
  2. 'CSharpDataDrivenTests.xml' - XML 테이블이 포함된 파일입니다.
  3. '#FirstTable' - '#' 구분 기호에 따라 'FirstTable' 값은 사용할 XML 문서 내의 특정 테이블을 식별합니다. TAEF는 지정된 값과 일치하는 'Id' 특성이 있는 Table 요소에 대한 XML 파일을 살펴봅니다.

두 번째 함수는 데이터 기반이 아닙니다. 일부 테스트만 데이터 기반이 되도록 선택할 수 있습니다. 또한 각 테스트에 테이블이 다른 XML 파일에 정의되어 있는 옵션도 있습니다.

줄 36에서는 VSTS에서 TestContext 클래스를 권장하는 것처럼 프라이빗 TestContext 속성을 정의합니다. 또한 이 속성에 대한 공용 평가자를 정의합니다(줄 30~34). 내부적으로 TAEF는 해당 데이터 집합이 포커스에 있는 TestContext의 사전 속성을 로드합니다.

TestContext는 Microsoft.VisualStudio.TestTools.UnitTesting에 정의되어 있습니다. 위의 예제에서 줄 3을 참조하세요. 관리되는 테스트 작성에 참조로 이미 포함해야 합니다. 따라서 데이터 기반 테스트를 작성하는 데 추가 참조가 필요하지 않습니다.

위 예제의 18줄에서는 함수에서 데이터를 검색하는 방법을 보여 줬습니다. 데이터는 m_testContext.DataRow에서 사용할 수 있습니다.

DataRow를 식별하기 위한 인덱스 대신 이름

TAEF를 사용하면 인덱스 대신 더 의미 있는 'Name' 속성을 사용하여 DataSource의 DataRow를 식별할 수 있습니다. 이렇게 하려면 DataSource의 행 수준에서 '이름' 메타데이터를 추가하기만 하면 됩니다. 이 페이지의 첫 번째 예제는 다음과 같이 이 기능을 사용하도록 수정할 수 있습니다.

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'와 연결되어 있습니다. 선택 쿼리를 사용하여 'Table1'에서 인덱스 0 또는 2를 찾을 수 있으며 올바른 행을 찾습니다. 그러나 dll을 실행하거나 나열할 때 다음을 보는 대신 다음을 수행합니다.

<qualified name of the test method>#<index>

대신 다음이 표시됩니다.

<qualified name of the test method>#<name property provided at Row level>

"Name" 특성이 행 수준에서 제공되는 행의 경우 위의 인덱스 1과 같이 행에 대해 "Name" 속성이 제공되지 않으면 기본적으로 메서드의 정규화된 이름에 #<index> 가 있습니다.

행 수준에서 "Name" 특성을 제공하는 방법으로 기본적으로 TAEF가 해당 행 데이터를 사용하여 메서드 호출의 instance 이름을 해석하는 방식을 변경합니다.

DataSource를 런타임 매개 변수로 사용

TAEF는 데이터 원본을 런타임 매개 변수로 제공할 수 있습니다. 이를 위한 구문은 다음과 같습니다.

te <test dll names> /p:<DataSource runtime name>=Table:<DataSoure XML file>#<Table Id>

관련 테스트를 작성하는 동안 "p:<DataSource 런타임 이름>"을 데이터 원본으로 지정해야 합니다. 런타임에 전체 문자열(XML 파일 이름 및 테이블 ID)을 함께 지정해야 합니다. 데이터 원본이 런타임에 제공되는 경우 TableId는 테스트 메타데이터로 제공되지 않을 것으로 예상됩니다. "Table:" 접두사는 테이블 데이터 원본을 찾고 있음을 지정합니다.

릴리스 공유에서 사용할 수 있는 예제 중 하나를 사용하여 이 작업을 시도할 수 있습니다.

te Examples\CPP.RuntimeDataSource.Example.dll /p:MyDataSource=Table:RuntimeDataSourceExample.xml#SimpleTable

DataSource를 리소스로

TAEF를 사용하면 다음을 준수하는 한 DataSource를 테스트 모듈의 리소스로 추가할 수 있습니다.

네이티브 테스트 모듈의 경우 DataSource를 리소스 ID 또는 리소스 이름으로 지정하여 이 작업을 수행할 수 있습니다. 여기에 코드 예제가 있습니다.

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 메타데이터 사양은 DataSource XML 파일을 지정하는 경우와 동일하게 유지됩니다. 관리 코드의 경우와 마찬가지로 리소스 이름을 XML 파일 이름과 동일하게 만들 수 있습니다. 따라서 TAEF가 먼저 DataSource 이름으로 실제 파일의 존재를 찾는다는 것을 이해하는 것이 중요합니다. 이러한 XML 파일을 찾을 수 없는 경우에만 지정된 리소스 이름 또는 ID를 사용하여 테스트 모듈에서 테스트 리소스를 찾습니다. DataSource를 리소스로 지정하려면 다시 컴파일해야 하므로 개발 중 DataSource XML 파일을 테스트 dll과 동일한 위치에 복사하고 리소스 이름을 XML 파일 이름과 동일하게 지정하여 이 디자인을 활용할 수 있습니다. 테스트가 완료되면 XML을 코드 디렉터리에 다시 복사하고 리소스로 다시 컴파일합니다. 실행 디렉터리에서 XML 파일을 삭제해야 합니다. :)

연습 예제

테이블 기반 데이터 기반 테스트의 다양한 측면을 파악하려면 몇 가지 연습 예제를 더 읽어보세요.