단위 테스트(unit test)는 보통 소스 코드의 일부를 테스트하려고 작성한다. 이론적으로, 이 조각이나 단위는 소스 코드에서 테스트 가능한 가장 작은 부분이다. 대개, 단위 테스트는 자동화되지만, 반드시 그런 것은 아니다. 단위 테스트의 결과는 코드가 설계한 대로 작동하는지를 알려준다.
소프트웨어 개발자는 늘 시간에 쫓긴다. 시장에 가능한 한 빨리 제품을 출시해야 한다는 엄청난 압박에 시달리는데, 왜 단위 테스트를 작성하는 데 시간을 더 소비해야 하는가? 대답은 충분한 단위 테스트 스위트(test suite)는 더 고품질의 코드를 생산할 뿐 아니라, 최종적으로는 버그를 고치는 데 시간이 덜 걸리기 때문에 시간을 절약한다. 더구나 애자일 개발 방법론을 따른다면 소스 코드를 작성하기 전에 단위 테스트를 작성하면 작성해야하는 코드 양이 줄어든다. 바로 코딩에 들어가기 전에, 설계하는 내내 어떻게 하는 것이 단위 테스트의 목표를 달성하려고 작성해야 하는 코드 양을 줄여주는지 생각해야 한다.
익스트림 프로그래밍이나 애자일 등에서 볼 수 있는 바와 같이, 단위 테스트의 지지자들이 많다. Ajax와 웹 2.0 사용자 인터페이스가 널리 사용되면서 클라이언트측 단위 테스트의 필요성이 대두되었다. DOH는 JUnit에 대한 웹 2.0 UI 개발자의 대답이다. JSUnit 같은 기존의 자바스크립트 단위 테스트 프레임워크와 달리, DOH는 자바스크립트 함수(Dojo를 사용하거나 말거나)를 위한 자동화된 프레임워크뿐 아니라 사용자 인터페이스의 실제 시각화(visualization)에 대한 단위 테스트도 제공한다. 이는 DOH(얼마나 멋진 약어인가!)가 테스트 프레임워크의 명령행과 브라우저 기반 인터페이스 둘 다 제공하기 때문이다.
앞에서 언급한 대로, DOH는 브라우저 기반 인터페이스뿐 아니라 명령행 인터페이스를 제공한다. 단위 테스트를 완전히 자동화해야 하고 시각적인 컴포넌트가 필요없다면, 빌드 스크립트에서 실행하고 결과를 기록할 수 있는 명령행 인터페이스를 사용하면 된다. 이 방식은 JUnit과 매우 비슷한 단위 테스트 환경을 제공한다. DOH는 명령행 인터페이스를 위해 자바(Java™)로 작성된 오픈 소스 자바스크립트 엔진인 Rhino를 사용한다. 그래서 document, window, DOMParser, 그리고 XMLHttpRequest 객체는 참조할 수 없다. Rhino로 인한 또 다른 문제점은 인기있는 브라우저와는 다른 자바스크립트 인터프리터를 사용하기 때문에, 어떤 런타임에서 통과한 테스트가 다른 런타임에서는 실패할 수도 있다는 점이다.
단위 테스트에 시각적인 컴포넌트나 다양한 자바스크립트 객체가 필요하다면, 브라우저 기반 인터페이스가 최선이다. 미리 말해두는데, 브라우저를 사용하는 단위 테스트는 100% 자동화되지 않는다. 원하는 브라우저에서 단위 테스트를 실행하고 결과를 확인해야만 한다. UI가 "잘" 보이는지 확인하는 것은 보통 인간의 주관적인 결정이므로, 그다지 놀랄 만한 일은 아니다. 브라우저 테스트 실행기는 단위 테스트 결과를 확인하는 두 가지 방법, 시각적인 결과와 단위 테스트 통계를 제공한다. 그림 1은 실행한 테스트 케이스를 왼쪽에, 코드 실행의 시각적인 결과를 오른쪽의 Test Page 탭 아래에 보여준다(그림 1 더 크게 보기).
그림 1. DOH 단위 테스트 시각화
그림 2는 Log 탭 아래에 단위 테스트 통계를 보여준다(그림 2 더 크게 보기).
그림 2. DOH 단위 테스트 통계
여러 가지 브라우저를 지원하는 클라이언트측 코드를 개발하려면, 단위 테스트를 통해 브라우저 간의 차이점을 재빨리 감지하는 능력이 중요하다. DOH 테스트 실행기는 HTML과 자바스크립트로 만들어졌기 때문에, 어떤 브라우저에서도 단위 테스트를 실행할 수 있다. 즉, 단위 테스트를 파이어폭스, 인터넷 익스플로러, 사파리(그리고 각 브라우저의 서로 다른 버전들)에서 실행할 수 있고 그 결과를 다른 것들과 비교할 수 있다. 기본적인 자바스크립트 메서드가 여러 가지 플랫폼에서 똑같이 동작하는지만 확인하는 것이 아니라, 다양한 플래폼에서 똑같거나 최소한 받아들일 수 정도로 보이는지를 확인할 수 있다. 어떤 브라우저에는 완벽하게 보이던 위젯이 다른 브라우저에서는 거의 알아볼 수 없는 경우를 겪어 본 적이 있을 것이다. 크로스 브라우저 버그는 짜증스럽고 고치기도 힘들다. 브라우저 호환성을 자동화된 방법으로 테스트하면 크로스 브라우저 지원 문제를 드러나게 하여, 소프트웨어가 시장에 나가기 전에 미리 미리 수정할 수 있다.
모든 테스트 프레임워크는 단위 테스트의 결과를 검사하는 메서드를 제공하며, DOH도 예외는 아니다. DOH는 테스트 검증에 사용할 세 가지 단언(assertion) API를 제공한다(Listing 1).
Listing 1. 세 가지 단언 API
doh.assertEqual(expectedResult, actualResult)
doh.assertFalse(testCondition)
doh.assertTrue(testCondition)
|
추가적으로, 이 함수들의 축약된 버전도 사용할 수 있다(Listing 2).
Listing 2. 단언 API의 축약된 버전
doh.is(expectedResult, actualResult)
doh.f(testCondition)
doh.t(testCondition)
|
단언이 실패하면 예외를 던진다. 단위 테스트에서 어떤 예외라도 발생하면 DOH는 전체 테스트가 실패한 것으로 간주한다. 예외가 발생해야만 하는 경우를 테스트하려면 코드를 try catch 블록으로 감싸야 한다. 단위 테스트가 호출될 때, DOH는 발생한 모든 에러와 실패한 특정 테스트를 알려준다. 또한, DOH는 실행한 테스트와 발생한 에러, 실패한 테스트의 총 개수도 알려준다.
DOH 에러 보고는 어떤 단언이 실패의 원인인지 결정하기 어렵게 설계되어 있으므로, 단위 테스트를 작성할 때 단언의 개수를 최소한으로 유지하는 것이 좋다. 일반적으로, equals 단언을 사용하면 실패의 원인을 결정하기 더 쉽고, true와 false 단언을 사용하면 원인을 찾기가 더 어렵다.
때때로 단위 테스트에서 발생한 에러들은 단언에 의해 발생하지 않는다. 이 경우에는, 그 단위 테스트나 테스트한 코드가 잘못된 것일 가능성이 높다. 파이어폭스용 애드온인 파이어버그를 사용하면 단위 테스트에서 발생하는 근본적인 코드 문제를 더 쉽게 디버깅할 수 있다.
DOH는 클라이언트측 애플리케이션이 만들어내는 비동기 호출의 동작을 단위 테스트할 수 있다. Ajax 요청의 동작을 테스트하는 것은 DOH의 가장 유용한 기능 중 하나다. DOH의 브라우저 기반 인터페이스는 XMLHttpRequest 객체를 사용할 수 있으므로, 비동기 단위 테스트를 지원한다. 테스트 케이스가 비동기임을 DOH에 알리려면 doh.Deferred 객체를 리턴하면 된다. DOH가 테스트가 비동기라는 것을 모른다면 테스트 코드를 실행한 후에 DOH는 테스트가 완료되었고 에러가 발생하지 않았다고 간주한다. 이것은 명백히 잘못된 결과이며, 코드의 일부는 테스트되지 않은 채로 남는다.
테스트 케이스 자체는 비동기 문맥을 이해하고 작성해야 한다. 단위 테스트 코드가 doh.Deferred 객체를 리턴하면 비동기 호출의 모든 에러를 잡아 doh.Deferred 객체의 errback 메서드에 전달해야 한다. 예외가 발생하지 않았다면 doh.Deferred 객체의 callback 메서드에 true 매개변수를 전달해야 한다. 이렇게 해야 DOH가 실패한 테스트를 정확하게 보고할 수 있다.
비동기 테스트를 더 쉽게 작성할 수 있도록, doh.Deferred 객체는 비동기 호출의 콜백 함수에서 발생하는 예외를 묵시적으로 처리하는 getTestCallback 함수를 제공하는데, 실행하고 싶언 단언을 포함한 테스트 함수를 getTestCallback에 전달하기만 하면 된다. 이렇게 하면 비동기 호출 과정에서 발생하는 예외를 직접 처리해야 하는 수고를 덜어준다. 더 자세한 내용은 테스트 스위트 작성하기를 참조하라.
DOH는 제한 시간을 밀리초 단위로 지정할 수 있는데, 지정한 시간 내에 응답이 반환되지 않으면 테스트가 실패한 것으로 간주한다. 비동기 테스트의 기본 제한 시간은 500 ms, 즉 0.5초지만, 테스트가 실패하지 않도록 더 긴 시간을 명시적으로 지정해주는 것이 좋다.
DOH를 사용하여 자신만의 테스트 스위트를 작성하는 것은 처음에는 어려워 보이겠지만, 알고 나면 그렇게 어렵지 않다. DOH 프레임워크가 테스트를 정의하고 불러오는 방법은 매우 융통성이 있어서, 불러오는 과정을 특정 구조에 맞게 고칠 수 있다. Dojo의 단위 테스트는 새 모듈 제작자가 선택하고 실행하기 쉽도록 하나의 공통 구조를 따른다. DOH 함수들에 익숙해질 때까지는 기존 관행을 따를 것을 권장한다.
예제 모듈인 demo.doh를 사용하여 테스트 케이스 구조를 설명한다. 이 모듈은 Dojo 디렉터리 구조에 맞게 위치하고 있다. 이렇게 하면 DOH 프레임워크가 Dojo 모듈 로더 구조를 그대로 사용하므로, 추가된 소스 코드 구조를 dojo에 알리려고 dojo.registerModulePath()를 사용하지 않아도 된다. util/doh/runner.html을 수정하여 모듈 경로를 추가할 수 있지만, doh.runner를 그대로 사용하고, Dojo의 디렉터리 구조에 맞추는 것이 더 쉽다. 그림 3은 이 절에서 설명할 일반적인 디렉터리 구조를 보여준다.
그림 3. 일반적인 디렉터리 구조
그림 3에서 볼 수 있는 것처럼, 각각의 dojo 모듈이 단위 테스트를 포함하는 것은 좋은 습관이다. 이렇게 하면 모듈 개발자는 전체 프로젝트와 별도로 단위 테스트를 실행할 수 있다. 즉, 로드하는 테스트 스위트 모듈 파일이 모든 모듈을 위한 모든 단위 테스트를 불러오지 않아도 된다. 그 방법은 구조의 기초를 자세히 설명한 다음, 뒤의 절에서 설명할 것이다.
테스트가 어떻게 동작하는지 본격적으로 알아보기 전에, 무엇을 테스트할 것인지를 봐두면 도움이 될 것이다. demo.doh는 도우미 함수와 간단한 DemoWidget을 담은 파일을 가진 모듈이다. 둘 모두를 포함한 것은 비시각적인 것(자바스크립트 함수)와 html에서 직접 쓰는 위젯을 테스트하는 법을 애플리케이션에서 쓰는 것처럼 효과적으로 보여주기 때문이다. 이 파일들은 이해하기 쉽도록 간단간 동작을 구현하고 있다. Listing 3은 demoFunctions.js의 내용이며, Listing 4는 DemoWidget.js의 내용이다.
Listing 3. demoFunctions.js의 내용
dojo.provide("demo.doh.demoFunctions");
//This file contains a collection of helper functions that are not
//part of any defined dojo class.
demo.doh.demoFunctions.alwaysTrue = function() {
// summary:
// A simple demo helper function that always returns the boolean true when
// called.
// description:
// A simple demo helper function that always returns the boolean true when
// called.
return true; // boolean.
};
demo.doh.demoFunctions.alwaysFalse = function() {
// summary:
// A simple demo helper function that always returns the boolean false when
// called.
// description:
// A simple demo helper function that always returns the boolean false when
// called.
return false; // boolean.
};
demo.doh.demoFunctions.isTrue = function(/* anything */ thing) {
// summary:
// A simple demo helper function that returns true if the thing passed in is
// logically true.
// description:
// A simple demo helper function that returns true if he thing passed in is
// logically true.
// This means that for any defined objects, or Boolean values of true, it
// should return true,
// For undefined, null, 0, or false, it returns false.
// thing:
// Anything. Optional argument.
var type = typeof thing;
if (type === "undefined" || thing === null || thing === 0 || thing === false) {
return false; //boolean
}
return true; // Boolean
};
demo.doh.demoFunctions.asyncEcho = function(/* function */ callback,
/* string */ message){
// summary:
// A simple demo helper function that does an asynchronous echo
// of a message.
// description:
// A simple demo helper function that does an asynchronous echo
// of a message.
// The callback function is called and passed parameter 'message'
// two seconds
// after this helper is called.
// callback:
// The function to call after waiting two seconds. Takes one
// parameter,
// a string message.
// message:
// The message to pass to the callback function.
if (dojo.isFunction(callback)) {
var handle;
var caller = function() {
callback(message);
clearTimeout(handle);
handle = null;
};
handle = setTimeout(caller, 2000);
}
};
|
Listing 4. demo/doh/DemoWidget.js의 내용
dojo.provide("demo.doh.DemoWidget");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("demo.doh.DemoWidget", [dijit._Widget, dijit._Templated],
//The template used to define the widget default HTML structure.
templateString: '<div dojoAttachPoint="textNode" style="width: 150px; ' +
' margin: auto; background-color: #98AFC7; font-weight: bold; color: ' +
'white; text-align: center;"></div>',
textNode: null, //Attach point to assign the content to.
value: 'Not Set', //Current text content.
startup: function() {
// summary:
// Overridden startup function to set the default value.
// description:
// Overridden startup function to set the default value.
this.setValue(this.value);
},
getValue: function() {
// summary:
// Simple function to get the text content under the textNode
// description:
// Simple function to get the text content under the textNode
return this.textNode.innerHTML;
},
setValue: function(value) {
// summary:
// Simple function to set the text content under the textNode
// description:
// Simple function to set the text content under the textNode
this.textNode.innerHTML = value;
this.value = value;
}
});
|
Listing 3과 4에서 간단한 위젯과 작은 독립형 함수들을 구현했다. 이제, 구현한 것들이 제대로 동작하는지 확인하기 위해 함수와 위젯을 시험하는 단위 테스트를 만들어보자. 다른 자바스크립트 단위 테스트 프레임워크를 사용하더라도 동기 함수는 쉽게 테스트할 수 있지만, 비동기 함수인 demo.doh.demoFunctions.asyncEcho와 위젯은 그렇지 못하다. DOH를 사용하여 동기 함수 테스트와 브라우저 내에서 위젯을 테스트하는 방법을 알아보자.
가장 간단한 독립적인 함수 테스트부터 시작하자. 독립적인 함수의 테스트 케이스를 작성하는 것은 자바스크립트 배열을 정의하는 것만큼이나 간단하다. 배열은 테스트 함수와 테스트 픽스처(fixture), 또는 둘 모두를 포함한다. 테스트가 얼마나 복잡하냐에 따라 어떤 것을 사용할지 결정하면 된다. 대부분의 경우에는, 간단한 테스트 함수가 테스트 코드에 더 적합하다. 테스트 픽스처를 만들 때 바꿀 필요가 있는 것은 제한 시간, 초기화(setup), 마무리(tearoff) 과정뿐이다. 테스트 스위트의 이름과 정의한 테스트 함수의 배열을 인자로 tests.register를 호출하여 DOH에 등록하자. Listing 5는 demoFunctions.js의 독립적인 함수들을 테스트하기 위한 코드다.
Listing 5. demo/doh/tests/functions/demoFunctions.js의 내용
dojo.provide("demo.doh.tests.functions.demoFunctions");
//Import in the code being tested.
dojo.require("demo.doh.demoFunctions");
doh.register("demo.doh.tests.functions.demoFunctions", [
function test_alwaysTrue(){
// summary:
// A simple test of the alwaysTrue function
// description:
// A simple test of the alwaysTrue function
doh.assertTrue(demo.doh.demoFunctions.alwaysTrue());
},
function test_alwaysFalse(){
// summary:
// A simple test of the alwaysFalse function
// description:
// A simple test of the alwaysFalse function
doh.assertTrue(!demo.doh.demoFunctions.alwaysFalse());
},
function test_isTrue(){
// summary:
// A simple test of the isTrue function
// description:
// A simple test of the isTrue function with multiple permutations of
// calling it.
doh.assertTrue(demo.doh.demoFunctions.isTrue(true));
doh.assertTrue(!demo.doh.demoFunctions.isTrue(false));
doh.assertTrue(demo.doh.demoFunctions.isTrue({}));
doh.assertTrue(!demo.doh.demoFunctions.isTrue());
doh.assertTrue(!demo.doh.demoFunctions.isTrue(null));
doh.assertTrue(!demo.doh.demoFunctions.isTrue(0));
},
{
//This is a full test fixture instead of a stand-alone test function.
//Therefore, it allows over-riding of the timeout period for a deferred test.
//You can also define setup and teardown function
//for complex tests, but they are unnecessary here.
name: "test_asyncEcho",
timeout: 5000, // 5 seconds.
runTest: function() {
// summary:
// A simple async test of the asyncEcho function.
// description:
// A simple async test of the asyncEcho function.
var deferred = new doh.Deferred();
var message = "Success";
function callback(string){
try {
doh.assertEqual(message, string);
deferred.callback(true);
} catch (e) {
deferred.errback(e);
}
}
demo.doh.demoFunctions.asyncEcho(callback, message);
return deferred; //Return the deferred. DOH will
//wait on this object for one of the callbacks to
//be called, or for the timeout to expire.
}
}
]);
|
Listing 5에서 볼 수 있는 것처럼, 기본 제한 시간을 변경하려면 테스트 픽스처가 필요하지만, 기본적인 테스트 스위트를 정의하는 데는 많은 코드가 필요없다. 위 코드는 테스트들은 또한 단위 테스트를 작성하는 다른 베스트 프랙티스를 보여준다. 테스트를 가능한 한 간단하고 작게 유지하라. 테스트마다 몇 안 되는 단언을 가지는 이유는, 그렇게 해야 테스트의 실패를 DOH 보고서의 에러 원인이 된 단언을 더 빨리 결정할 수 있기 때문이다. 단언을 너무 많이 사용하면 어느 단언이 에러를 유발했는지 알아내기 결정하기 어렵다.
위 코드에서 언급할 만한 다른 흥미로운 부분은 비동기 테스트를 작성하는 방법이다. 콜백은 나중에 비동기로 실행되므로, 실패했을 때 동기 테스트에서 했던 것처럼 try/catch로는 잡을 수 없으므로, 이를 고려하여 단위 테스트를 작성해야 한다. asyncEcho 테스트에서는, 단언을 try/catch로 감싸고 있으며, 발생하는 모든 에러는 deferred.errback(error) 호출을 통해 DOH에 다시 전달된다. try/catch로 감싸지 않으면 에러로 인해 테스트가 실패하더라도 DOH는 테스트 시간 초과로 간주한다. 단언이 실패할 때 발생한 에러가 deferred.callback() 실행을 막기 때문에, DOH는 완료를 보고하지 않으며, 결국 제한 시간 초과가 되는 것이다. 즉, 비동기 테스트가 통과하거나 실패했는지를 DOH에 알려주는 유일한 방법은 Deferred의 해당 메서드를 호출하는 것이다.
앞 절에서 본 것처럼, 간단한 독립적인 함수를 테스트하는 것은 쉽다. 테스트 함수나 픽스처의 배열을 만들어 등록하면, DOH가 그것들을 로드하고 실행한다. 이것만 해도 좋지만, 독립적인 함수와 비시각적인 코드가 자바스크립트의 전부는 아니다. 더 인터랙티브한 룩앤필을 제공하기 위해 브라우저의 DOM을 조작하는 위젯을 테스트하는 방법을 알아보자.
DOH는 웹 브라우저가 테스트할 위젯을 초기화하는 HTML 파일을 불러오면 테스트를 등록하는 좋은 프레임워크와 메서드를 제공한다는 것이다. 실질적으로, DOH가 하는 것은 iframe 안의 HTML 파일 안에서 실행되는 DOH의 인스턴스를 UI와 독립적인 테스트를 실행하는 DOH 인스턴스를 연결하는 것이다. 독립적인 함수 테스트와는 달리, 위젯 테스트는 일반적으로 Rhino 같은 자바스크립트 인터프리터를 통해 실행할 수 없다는 점을 기억해 두자.
위젯 테스트를 정의하려면, DOH를 생성하고, 위젯을 생성하는 HTML 파일을 정의한 다음, 실행할 테스트 함수를 정의한다. Listing 6은 DOH를 사용하여 demo.doh.DemoWidget 위젯을 테스트하는 HTML 파일을 보여준다.
Listing 6. demo/doh/tests/widgets/DemoWidget.html의 내용
<html>
<head>
<title>DemoWidget Browser Tests</title>
<script type="text/javascript" src="../../../../dojo/dojo.js"
djConfig="isDebug: true, parseOnLoad: true"></script>
<script type="text/javascript">
dojo.provide("demo.doh.tests.widgets.DemoWidgetHTML");
dojo.require("dojo.parser");
dojo.require("doh.runner");
dojo.require("demo.doh.DemoWidget");
dojo.addOnLoad(function(){
doh.register("demo.doh.tests.widgets.DemoWidget", [
function test_DemoWidget_getValue(){
// summary:
// Simple test of the Widget getValue() call.
doh.assertEqual("default", dijit.byId("demoWidget").getValue());
},
function test_DemoWidget_setValue(){
// summary:
// Simple test of the Widget setValue() call.
var demoWidget = dijit.byId("demoWidget");
demoWidget.setValue("Changed Value");
doh.assertEqual("Changed Value", demoWidget.getValue());
}
]);
//Execute D.O.H. in this remote file.
doh.run();
});
</script>
</head>
<body>
<!-- Define an instance of the widget to test. -->
<div id="demoWidget" dojoType="demo.doh.DemoWidget" value="default"></div>
</body>
</html>
|
Listing 6은 DOH를 실행하는 독립적인 파일이다. 멋지긴 하지만, DOH의 UI를 표시하지 않으므로, 테스트가 통과했는지 아닌지 말하기 어렵다. DOH는 HTML 파일을 실행 중인지. 그리고 UI를 출력하는지 알려주는 메커니즘을 제공한다. DOH가 제공하는 또 다른 테스트 등록 함수인 doh.registerUrl()을 사용하면 별도의 HTML인 DOH의 runner.html UI를 지정할 수 있다. 그 다음에 해야 할 일은 그 HTML 파일을 frame에 불러오고, 그 HTML 파일 안에서 생성된 DOH 인스턴스를 UI의 DOH 인스턴스와 연결하면, DOH는 UI를 통해 HTML 페이지의 실패와 성공을 출력할 수 있다! Listing 7은 테스트의 원본과 결과로 URL을 등록하는 모듈 파일 코드를 보여준다.
Listing 7. demo/doh/tests/widgets/DemoWidget.js의 내용
dojo.provide("demo.doh.tests.widgets.DemoWidget");
if(dojo.isBrowser){
//Define the HTML file/module URL to import as a 'remote' test.
doh.registerUrl("demo.doh.tests.widgets.DemoWidget",
dojo.moduleUrl("demo",
?쐂oh/tests/widgets/DemoWidget.html"));
}
|
총정리: 테스트 정의를 하나의 DOH 테스트 스위트로 합치기
지금까지 개별적인 테스트 파일을 작성하는 방법을 배웠다. 예제에서 본 것처럼, 단일 테스트를 작성하는 것은 복잡하지 않다. 그러면, 이제 테스트 정의들을 합쳐 DOH의 UI에 불러오고, 테스트를 실행하는 방법을 알아보자. 이것도 어렵지 않다. DOH의 runner.html로 리디렉트(redirect)하는 HTML 파일을 하나 작성하자. 리디렉트의 일부로, 불러올 자바스크립트 모듈 파일을 지정하는 쿼리 매개변수를 넘겨주어야 한다. 흔히 module.js라 부르는 이 단일 모듈 파일은 dojo.require()를 사용하여 테스트 파일 각각을 불러온다. dojo.require()가 해당 파일을 불러 올 때, 파일에 포함된 테스트들을 등록한다. 모든 테스트 파일을 불러온 다음 DOH 프레임워크는 등록된 테스트들을 자동으로 실행한다. Listing 8은 리디렉션 파일이다. Listing 9는 모든 테스트를 불러오는 moudle.js 파일이다.
Listing 8. demo/doh/tests/runTests.html의 내용
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>demo.doh Unit Test Runner</title>
<meta http-equiv="REFRESH"
content="0;url=../../../util/doh/runner.html?testModule=demo.doh.tests.module">
</head>
<body>
Redirecting to D.O.H runner.
</body>
</html>
|
Listing 9. demo/doh/tests/module.js의 내용
dojo.provide("demo.doh.tests.module");
//This file loads in all the test definitions.
try{
//Load in the demoFunctions module test.
dojo.require("demo.doh.tests.functions.demoFunctions");
//Load in the widget tests.
dojo.require("demo.doh.tests.widgets.DemoWidget");
}catch(e){
doh.debug(e);
}
|
DOH가 초심자에겐 어려울 수 있지만, 융통성 있고 강력한 단위 테스트 프레임워크다. 테스트를 별도로 불러올 수 있는 파일로 모듈화하고, 테스트를 그룹으로 묶을 수 있으며, 실행될 코드의 조건을 단언하기 위한 일련의 API들을 제공하고, 심지어 비동기 테스트와 브라우저에서 URL 등록과 iframe 페이지 로딩을 통해 위젯을 테스트할 수 있는 프레임워크를 제공한다.
DOH를 조각 조각 살펴보면 복잡함은 사라진다. 간단한 테스트 케이스는 빠르고 쉽고 작성할 수 있으며, 그 테스트들을 하나의 스위트로 묶는 것은 테스트의 분리된 각 모듈을 dojo.require()하는 자바스크립트 파일을 하나 더 만드는 것에 불과하다. 이렇게 만들어진 모듈 파일은 테스트 스위트의 진입점이 된다. 이 파일을 쿼리 매개변수로 지정하여 runner.html을 불러오면 테스트가 실행된다.
마지막으로, DOH는 브라우저 환경에 제한되지 않는다. 기본적인 DOH 로더와 프레임워크는 SpiderMonkey와 Rhino 같은 헤드리스(headless) 자바스크립트 환경에서도 사용할 수 있다. DOH는 자바스크립트 코드를 테스트하기 위한 가장 완전하고 효과적인 프레임워크 중 하나다.
| 설명 | 이름 | 크기 | 다운로드 방식 |
|---|---|---|---|
| 소스 코드 | demo.doh.zip | 5KB | HTTP |
- Dojo 툴킷 웹 사이트에서 Dojo와 Dojo Objective Harness에 대한 문서를 볼 수 있다.
- Dustin Machi는 DOH를 이용한 단위 테스트에 대한 통찰력 있는 블로그 글을 썼다.
- 단위 테스트에 대해 더 자세히 알아보자.
- Rhino는 DOH가 사용하는 자바 기반 자바스크립트 인터프리터다.
- 애자일 소프트웨어 개발과 익스트림 프로그래밍은 둘 다, 소스 코드를 작성하기 전에 단위 테스트 케이스를 작성하도록 장려한다.
- developerWorks의 Ajax 참고자료 센터에서 다른 Ajax 기술(Dojo를 포함한)에 대한 더 자세한 정보를 찾을 수 있다.
- Dojo API의 완전한 레퍼런스를 얻을 수 있다.

