단위 테스트
단위 테스트 (Unit Tests)
단위 테스트(unittest)는 모듈이 올바르게 동작하는지 확인하기 위한 내장 테스트 프레임워크예요. D 프로그램은 단위 테스트를 켜거나 끄고 실행할 수 있고, 단위 테스트는 컴파일러 스위치(-unittest)로 켜요. 이 문서는 단위 테스트 작성 문법과 속성(attribute) 부여, 그리고 문서화된 단위 테스트(Documented Unittests)를 다루어요.
출처: Unit Tests
본문
단위 테스트는 모듈에 적용되는 테스트 케이스의 내장 프레임워크예요. D 프로그램은 단위 테스트를 활성화하거나 비활성화한 상태로 실행할 수 있어요.
단위 테스트는 다음과 같이 정의하는 특별한 함수예요:
UnitTest:
unittest BlockStatement
unittest
{
...test code...
}
개별 테스트는 단위 테스트 안에서 AssertExpression을 사용해 지정해요. 다른 곳에서 쓰는 AssertExpression과 달리, 여기서 assert는 참이라고 가정되지 않으며, assert가 실패해도 프로그램은 여전히 정의된 상태(definite state)에 있어요.
모듈 안에는 단위 테스트 함수를 몇 개든 둘 수 있어요. 여기에는 struct, union, class 선언 안의 단위 테스트도 포함돼요. 단위 테스트는 어휘적 순서(lexical order)로 실행돼요.
단위 테스트는 활성화되었을 때 모든 정적 초기화(static initialization)가 완료된 뒤, main() 함수가 호출되기 전에 실행돼요.
예를 들어 두 값을 더하는 Sum 클래스가 있을 때, 다음과 같은 단위 테스트를 줄 수 있어요:
class Sum
{
int add(int x, int y) { return x + y; }
unittest
{
Sum sum = new Sum;
assert(sum.add(3,4) == 7);
assert(sum.add(-2,0) == -2);
}
}
단위 테스트가 활성화되면 unittest 버전 식별자(version identifier)가 미리 정의돼요.
속성이 부여된 단위 테스트 (Attributed Unittests)
unittest에는 전역 함수 속성(global function attributes) 중 아무거나 부여할 수 있어요. 이런 단위 테스트는 템플릿 함수에 부여된 특정 속성(들)을 검증할 때 유용해요:
void myFunc(T)(T[] data)
{
if (data.length > 2)
data[0] = data[1];
}
@safe nothrow unittest
{
auto arr = [1,2,3];
myFunc(arr);
assert(arr == [2,2,3]);
}
이 단위 테스트는 myFunc가 @safe, nothrow 코드만 포함함을 검증해요. 이 속성들을 myFunc 자체에 붙여도 같은 결과를 얻을 수 있지만, 그렇게 하면 myFunc가 opAssign 메서드나 myFunc가 호출할 수 있는 다른 메서드에 @system이거나 던지는(throwing) 코드가 있는 타입 T로는 인스턴스화되지 못해요. 위의 관용구(idom)는 myFunc가 그런 타입으로 인스턴스화되는 것을 허용하면서도, 동시에 @system 및 던지는 동작이 myFunc 자체 내부 코드에 의해 도입되지 않음을 검증할 수 있어요.
Implementation Defined: (구현 정의 사항)
- 단위 테스트가 활성화되지 않았다면, 구현은 UnitTest의 문법적·의미적 정확성을 검사할 필요가 없어요. 이는 더 큰 단위 테스트 구간의 컴파일 시간 영향을 줄이기 위함이에요. 토큰은 여전히 유효해야 하며, 구현은 단순히
{와}토큰을 세어서 UnitTest의 BlockStatement 끝을 찾을 수 있어요.- 사용자에게 단위 테스트 결과를 보여주는 방식.
- 단위 테스트를 켜거나 끄는 방법.
-unittest같은 컴파일러 스위치를 사용해 활성화하는 것을 권장해요.- 모듈들이 자신의 단위 테스트를 실행하기 위해 호출되는 순서.
- 프로그램이 첫 번째 단위 테스트 실패에서 멈출지, 아니면 나머지 단위 테스트를 계속 실행할지.
Best Practices: (모범 사례)
- 단위 테스트를 커버리지 테스트(예:
-cov)와 함께 사용하는 것이 효과적이에요.- 어떤 함수의 단위 테스트는 그 함수 바로 뒤에 나타나야 해요.
문서화된 단위 테스트 (Documented Unittests)
문서화된 단위 테스트는 개발자가 사용자에게 코드 예제를 전달하면서, 동시에 그 예제가 유효함을 자동으로 검증할 수 있게 해줘요. 이는 일부 코드에 대한 문서가 낡아지는 흔한 문제를 피하게 해줘요.
선언 다음에 문서화된 단위 테스트가 오면, 그 단위 테스트의 코드가 선언의 예제(example) 섹션에 삽입돼요:
/// Math class
class Math
{
/// add function
static int add(int x, int y) { return x + y; }
///
unittest
{
assert(add(2, 2) == 4);
}
}
///
unittest
{
auto math = new Math();
auto result = math.add(2, 2);
}
위 코드는 다음과 같은 문서를 생성해요:
class Math;
Math class
Example:
auto math = new Math;
auto result = math.add(2, 2);
int add(int x, int y);
add function
Example:
assert(add(2, 2) == 4);
문서화되지 않은 단위 테스트나 private으로 표시된 단위 테스트는 코드 샘플을 생성하는 데 사용되지 않아요.
문서화된 단위 테스트는 여러 개일 수 있고 어떤 순서로든 나타날 수 있어요. 그것들은 마지막 non-unittest 선언에 연결돼요:
/// add function
int add(int x, int y) { return x + y; }
/// code sample generated
unittest
{
assert(add(1, 1) == 2);
}
/// code sample not generated because the unittest is private
private unittest
{
assert(add(2, 2) == 4);
}
unittest
{
/// code sample not generated because the unittest isn't documented
assert(add(3, 3) == 6);
}
/// code sample generated, even if it only includes comments (or is empty)
unittest
{
/** assert(add(4, 4) == 8); */
}
위 코드는 다음과 같은 문서를 생성해요:
int add(int x, int y);
add function
Examples:
code sample generated
assert(add(1, 1) == 2);
Examples:
code sample generated, even if it is empty or only includes comments
/** assert(add(4, 4) == 8); */