Tech/Silverlight2009. 5. 19. 15:15

참고 자료 _ Unit Testing with Silverlight 2
원문 _ Silverlight2 Unit Test


1. Unit Test 환경 만들기
2. API Unit Test
3. UI Unit Test


1. Unit Test 환경 만들기

Silverlight에서 UnitTest 환경을 구축하기 위해서는 우선 UnitTest Framework을 준비해야 한다.
Framework는 MSDN에서 다운로드 받을 수 있다Microsoft Silverlight Unit Test Framework
(UnitTest를 위한 Template도 같이 받아두면 편리하다.)


다운로드 받은 Framework 파일은 아래 경로에 복사한다.
(Microsoft.Silverlight.Testing.dll, Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll)

%programfiles%\Microsoft SDKs\Silverlight\v2.0\Libraries\Client

다운로드 받은 Template 파일은 유저 템플릿으로 등록한다.
Template 파일의 압축을 풀어보면 Project Template과 Class Template으로 나뉘는데 각각을 아래 경로에 복사한다. (압축 파일 자체를 복사하면 된다.)

Project Template _ %userprofile%\Documents\Visual Studio 2008\Templates\ProjectTemplates
Class Template _ %userprofile%\Documents\Visual Studio 2008\Templates\ItemTemplates

<주의사항>
현재 최신 버전의 Framework에 포함된 dll 파일의 버전이 Template에 명시된 버전과 다른 문제가 있다.
정상적으로 사용하기 위해서는 Template의 내용을 수정해야 하는데, Template 파일의 압축을 풀고 각각의 Template 별로 아래의 내용을 수정하자.

2009.3.10 기준으로 
Microsoft.Silverlight.Testing.dll의 버전은 2.0.21103.1925, Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll의 버전은 2.0.21024.1838 이다.

Project Template _ SilverlightTestProject.csproj 파일을 열고 각각의 Reference 버전을 수정한다.
Class Template _ MyTemplate.vstemplate 파일을 열고 각각의 Assembly 버전을 수정한다.

위 작업이 다 끝난 이후에 Visual Studio 2008을 실행시켜보면
새 프로젝트 생성시 Visual C# 카테고리를 선택하면 내 템플릿에 Silverlight Test Project가 생성되어 있고
프로젝트에 Class 추가를 실행하면 Visual C# 카테고리의 내 템플릿에 Silverlight Test Class가 등록되어 있는 것을 확인할 수 있다.



2. API Unit Test

UnitTest를 위해 UnitTestApp 라는 이름을 가진 Silverlight Application을 생성한다.
UnitTestApp에 MyTestClass 클래스를 추가하고 아래와 같은 함수를 구현한다.

public int add(int value1, int value2)
{
    return value1 + value2;
}

이제 add 함수를 테스트 하기 위해서 실제로 UnitTest를 수행할 프로젝트를 생성한다.
UnitTestApp 솔루션에 Test라는 새 프로젝트를 추가한다. (템플릿은 Silverlight Test Project를 선택한다)

생성된 Test.cs 파일을 살펴보면 Test Class 앞에는 [TestClass]가 선언 되어 있고 테스트 함수 앞에는 [TestMethod]가 선언 되어있는 것을 알 수 있다.

Test 프로젝트를 실행하면 [TestClass]로 선언된 Class 안에 포함된 [TestMethod]를 수행하여 실제 UnitTest를 수행하게 된다.

아래와 같은 Test 함수를 추가하여 add 함수를 테스트 한다.

[TestMethod]
public void AddTest()
{
MyTestClass myTestClass = new MyTestClass();
Assert.AreEqual(3, myTestClass.add(1, 2));
}

이때 MyTestClass는 Test 프로젝트에 포함되어 있지 않기 때문에 Test 프로젝트 참조에 UnitTestApp를 추가하고 Test.cs에 using UnitTestApp; 를 추가해야 정상적으로 빌드 된다.


빌드가 완료되어 Test 프로젝트를 실행하면 다음과 같은 화면을 통해 테스트가 정상적으로 수행 되었음을 알 수 있다.


테스트 오류 상황을 확인하기 위해 Assert.AreEqual(3, myTestClass.add(1, 2)); 부분을 Assert.AreEqual(5, myTestClass.add(1, 2)); 로 수정해본다. 수정 후 실행 결과는 다음과 같다.


AddTest 함수에서 오류가 발생한 것을 알 수 있으며 기대값과 실제 값을 확인할 수 있다. 이때 AddTest를 클릭하면 더 자세한 정보를 확인할 수 있다.

다음은 컬렉션의 값이 추가 되었을때 정상적으로 이벤트가 발생하는지 테스트하는 항목을 만들어본다.
MyTestClass에 다음과 같은 멤버 변수와 함수를 추가한다.

internal ObservableCollection<int> collection = new ObservableCollection<int>();

public void addCollection(int value)
{
collection.Add(value);
}

그리고 addCollection 함수를 테스트 하기 위해 Test 프로젝트의 Test 클래스에 다음과 같은 Test 함수를 추가한다.
테스트 내용은 addCollection을 한번 호출하였을 때 Collection의 값이 변동이 되었다는 이벤트를 받아 이벤트가 정상적으로 발생 되었는지, Collection에 포함된 자료의 갯수가 한개인지 확인하게 된다.

[TestMethod]
public void CollectionTest()
{
MyTestClass myTestClass = new MyTestClass();

bool changedValue = false;

myTestClass.collection.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs e)
{
changedValue = true;
Assert.AreEqual(NotifyCollectionChangedAction.Add, e.Action);
Assert.AreEqual(1, e.NewItems.Count);
};

myTestClass.addCollection(5);
Assert.IsTrue(changedValue);

}

이 코드를 추가하고 다시 빌드를 실행하면 internal로 선언된 collection 때문에 오류가 발생한다. 이는 Test 프로젝트와 UnitTestApp가 서로 다른 namespace이기 때문인데, 테스트를 위해서 collection을 public으로 바꾸는 방법도 있지만, UnitTestApp에 있는 AssemblyInfo.cs 파일을 수정하여 UnitTestApp에 있는 internal 을 Test 어셈블리에서도 access 가능하게 수정하도록 한다.

internal로 선언된 변수를 다른 어셈블리에 공개하려면 AssemblyInfo.cs 파일에 다음을 추가하면 된다. (AssemblyInfo.cs 파일은 Properties 폴더에 있음)

[assembly: InternalsVisibleTo("Test")]

빌드가 정상적으로 되고 Test 프로젝트를 실행하면 정상적으로 테스트를 성공하는 것을 확인할 수 있다.


3. UI Unit Test

UI를 테스트 하기 위해서는 테스트 대상이 될 어플리케이션을 임시로 생성하고 사용자 입력을 자동으로 만들어서 테스트를 수행하여야 한다.

UnitTestApp의 Page.xaml에 다음과 같은 코드를 생성하자.

<StackPanel>
<TextBox x:Name="InputText" />
<Button Content="Click" Click="Button_Click" />
<TextBlock x:Name="OutputText" />
</StackPanel>

Button을 클릭하면 InputText에 있는 내용을 OutputText로 뿌려주도록 한다.

private void Button_Click(object sender, RoutedEventArgs e)
{
OutputText.Text = InputText.Text;
}

구현한 위의 동작을 테스트 하기 위해서 Test 프로젝트에 새로운 테스트 클래스인 UITest를 생성하자. (Silverlight Test Class 템플릿을 사용)

UITest를 이용해서 어플리케이션의 UI를 테스트 하기 위해서는 [TestMethod]가 수행될 때마다 어플리케이션을 임시로 생성해야 하는데, 이것은 [TestInitialize]를 이용하여 할 수 있다. 함수 앞에 [TestInitialize]를 선언하면 그 함수는 [TestMethod]가 수행될때마다 [TestMethod]이전에 실행되어서 원하는 값들을 초기화 시킬 수 있다.
(초기화 뿐만 아니라 [TestCleanup]을 이용하여 [TestMethod] 수행 종료 이후에 테스트 후의 환경을 정리할 수도 있다.)

[TestInitialize] -> [TestMethod] -> [TestCleanup] 순서로 수행 됨

실제로 테스트를 수행하기 위해서는 [TestInitialize] 함수에서 UnitTestApp의 페이지를 생성하고, 그 페이지를 SilverlightTest 클래스안에 있는 TestPanel의 Children에 추가시켜야 한다. 이것을 위해서 실제 테스트 클래스를 SilverlightTest를 상속받는 클래스로 생성한다.

using UnitTestApp;
using Microsoft.Silverlight.Testing;

[TestClass]
public class UITest : SilverlightTest
{
private Page testPage;

[TestInitialize]
public void PreparePage()
{
testPage = new Page();
TestPanel.Children.Add(testPage);
}
}

준비가 끝났으면 실제 테스트를 수행하는 함수를 작성한다.

[TestMethod]
public void TextBoxTest()
{
testPage.InputText.Text = "TextBoxTest";
testPage.Button_Click(this, null);

Assert.AreEqual("TextBoxTest", testPage.OutputText.Text);
}

빌드를 해보면 오류가 발생한다. Page.xaml.cs 파일을 보면 Button_Click이 private으로 선언 되어 있는데 이것을 internal로 수정한다.
(internal로 수정해서 빌드가 가능한 이유는 AssemblyInfo.cs 파일에 Test 어셈블리를 internal 범위에 포함시켰기 때문이다. internal 범위에 포함시키지 않았다면 testPage의 InputText나 OutputText도 사용할 수 없다.)

빌드가 정상적으로 진행되어 실행해보면, 작성한 Page.xaml의 내용이 화면에 깜박거리면서 테스트가 진행되는 것을 볼 수 있으며 다음과 같은 결과를 확인할 수 있다. (실제로는 UI 화면이 깜박거리면서 사라진다.)




이 포스팅에 사용된 샘플 소스

저작자 표시

'Tech > Silverlight' 카테고리의 다른 글

Silverlight 3 _ 3D  (0) 2009.06.18
ImageButton 만들기  (0) 2009.06.11
Rhino Mocks in Silverlight  (2) 2009.05.15
DataGrid 사용법  (0) 2009.04.06
Posted by wafe