SqueakByExample:7.6
SUnit 프레임웍
SUnit은 4개의 메인클레스로 구성되어 있습니다: TestCase, TestSuite, TestResult, TestResource 인데 그림 7.2 에서 확인할 수 있습니다. 테스트 리소스의 개념은 구성하는데 많은 비용이 들기는 하지만 테스트의 시리즈에 리소스로 사용되기 위해 SUnite 3.1부터 등장했습니다. TestResource 는 테스트들의 suite 이전에 한번만 실행되는 setUp 메서드를 명시합니다; TestResource는 각 테스트 전에 실행되는 TestCase>>setUp 에 대해서 고유합니다.
TestCase
TestCase 는 하위 클래스가 되도록 설계된 임의의 클래스 이며 그 하위 클래스들 각각은 공통된 컨텍스트(테스트 suite)를 공유하는 테스트들의 그룹을 나타냅니다. 각 테스트는 TestCase, 실행중인 setup, 실행중인 테스트 메서드 자체, 그리고 실행중인 tearDown의 하위 클래스의 새로운 인스턴스를 만들어서 실행됩니다.
컨텍스트는 하위 클래스의 인스턴스 변수들과 메서드 setUp 의 특화로 지정되며, 이러한 컨텍스트의 지정 동작은 인스턴스 변수들을 초기화합니다. TestCase 의 하위 클래스들은 tearDown 메서드를 재지정할 수 있으며, 이러한 재지정작업은 각 테스트의 실행 후에 호출되고, setUp 을 실행하는 동안 모든 할당된 객체들을 릴리즈 하기 위해 사용될 수 있습니다.
TestSuite
TestSuite 클래스의 인스턴스들은 test cases 의 컬렉션을 포함합니다. TestSuite 의 인스턴스는 테스트들과 다른 테스트 suite 를 포함하고 있습니다. 즉 테스트 suite는 TestCase 와 TestSuite 의 하위인스턴스를 포함하고 있다는게 됩니다. 각각의 TestCases 와 TestSuites 는 같은 프로토콜을 알아들을 수 있기때문에, 같은방식으로 취급하는것도 가능합니다; 예를 들면 양쪽다 실행이 가능하다는 것이죠. 사실 이런것들이 가능한 이유는, TestSuite 는 TestCases 의 일부와 합성을 통한 composite 패턴의 어플리케이션이기 때문입니다.- composite 패턴에 대한 좀 더 많은 정보를 보시려면 Design Patterns[1] 를 봐주시기 바랍니다.
TestResult
TestResult 클래스는 TestSuite 실행의 결과를 나타냅니다. 이 클래스는 통과한 테스트들의 개수, 실패한 테스트들의 개수 그리고 발생한 오류의 갯수등을 기록합니다.
TestResource
테스트 suite 의 중요한 특징 중 하나는 테스트는 각각 독립적이어야 한다는 점입니다: 한 개의 테스트의 실패때문에 다른 테스트들이 대량으로 실패되는 현상이 일어나서는 안되며, 또한 테스트들은 서로의 실행 순서에 영향을 미쳐서도 안됩니다. 각 테스트를 진행하기전에 setUp 을 사용하거나 테스트뒤에 tearDown 을 쓰는건 각 테스트사이의 독립성을 강화하는데 도움이 됩니다.
하지만, 가끔 테스트를 실행하기전 한번 유용하게 사용되어야 하는데 필요한 컨텍스트를 설정하는 작업이 너무나 시간을 잡아먹어서 사용하기 힘든때가 있죠. 더군다나, 이런 테스트 케이스가 테스트에서 사용하는 리소스에 지장을 주지않는다는것을 알게된다면 각각의 테스트를 위해 컨텍스트를 다시 설정하는 작업은 시간낭비입니다; 이런경우 테스트의 각 suite 는 한번만 설정하는것으로 충분합니다. 예컨데, 테스트들의 suite 가 데이터 베이스를 조회할 필요가 있거나 몇몇 컴파일한 코드에 대한 분석을 시행해야 할 필요가 있다고 가정해 보도록 합니다. 이런경우, 실행할 모든 테스트를 시작하기 전에 데이터 베이스를 먼저 설정하고, 데이터베이스에 대한 연결을 열거나 또는 몇몇 소스 코드를 컴파일하는 작업이 좋은 실행법입니다.
대체 어디로 이러한 자원을 캐쉬해야, 테스트 suite 들이 공유할 수 있을까요? 특정 인스턴스 변수는 TestCase 의 하위인스턴스가 될 수 없는데, 왜냐하면 이런 인스턴스(변수)는 오직 테스트를 진행하는 과정에서만 존재되기 때문입니다. 글로벌 변수라면 항상 존재하기때문에 리소스의 용도로 사용이 가능합니다만, 많이 쓰는경우 namespace 가 복잡해지며, 글로벌 변수와 테스트사이의 의존성의 강제되는것도, 별도로 명시되는것도 아니기때문에 클로벌변수의 리소스 사용은 권장할만한 방법은 아닙니다. 보다 좋은 방법이 있는데, 필요한 리소스를 몇몇 클래스들의 singleton 오브젝트에 집어 넣는 거죠. 이런 경우에 사용하기 위해 리소스클래스로 TestResource 클래스가 준비되어있습니다. TestResource 의 하위 클래스로 생성된 singletone 인스턴스에 대해 current 메시지를 사용할 수 있으며, current 메시지 사용시 해당되는 singleont 인스턴스가 응답하게 됩니다. 반드시 테스트의 리소스가 생성 되고 소멸되도록 하기 위해 setUp 메서드와 tearDown 메서드는 하위 클래스 내부에서 재정의되어야 합니다.
한가지더: SUnit 은 어떤 테스트 suite 와 어떤 리소스가 연관되었는지에 관해 어느 정도는 알고 있어야만 합니다. 리소스는 클래스 메서드 리소스를 재정의함으로써 TestCase 의 특정 하위 클래스와 연관됩니다. TestSuite 의 리소스는 기본적으로 그것이 포함하고 있는 TestCases 의 리소스와 묶여집니다.
예제를 보도록 하겠습니다. TestResource 의 하위 클래스로서 MyTestResource 를 정의하고, MyTestCase 의 클래스 메소드인 resources 를 오버라이드 해서 미리 생성한 리소스인 MyTestResource 의 배열이 반환되도록 합니다.
클래스 7.9: TestResource 하위 클래스의 예
TestResource subclass: #MyTestResource
instanceVariableNames: ''
MyTestCase class>>resources
"associate the resource with this class of test cases"
↑{ MyTestResource }
Notes
- ↑ Erich Gamma et al., Design Patterns: Elements of Reusable Object-Oriented Software. Reading, Mass.: Addison Wesley, 1995, ISBN 0–201–63361–2–(3).