AngularJs Test
AngularJs로 작성한 코드를 테스트하는 방법을 정리했습니다.
AngularJs에 대한 이해
AngularJs는 자바스크립트를 구동하는 프레임워크이므로 암묵적으로 작동하는 코드들이 있습니다.
그렇기 때문에 AngularJs에 대한 간단한 이해가 있어야 테스트 코드를 작성할 수 있습니다.
구성
AngularJs는 기본 설정을 하는 Bootstrap과정이 있고, 그 과정에서 Router설정을 할 수 있습니다.
여기서 Bootstrap이란 프로그램의 실행 환경을 설정하는 것을 말하고
Router설정은 각 URL별로 어떤 뷰를 보여줄지 정하는 방식입니다.
그리고 Bootstrap과정에서 컨트롤러, 서비스, 팩토리, 지시자 등을 조합해서 전체 프로그램이 구성됩니다.
이와 관련된 내용은 AngularJs 공식 홈페이지 Developer Guide를 참고하면 됩니다.
Jasmine & Karma Test
AngularJs는 기본적으로 자스민으로 테스트 코드를 작성합니다.(공식 홈페이지 기준)
테스트 어려운 형태 테스트
AngularJs에서 테스트를 할 때 기본적인 사항은 기본 자스민 테스트방식과 유사하며,
이는 자스민 공식홈페이지나 블로그 글을 참고하시면 됩니다.
테스트 케이스 기본설정
AngularJs로 테스트케이스를 작성할 때 가장 난감한 부분이 테스트 환경을 구축하는 부분입니다.
이는 AngularJs에서 app에 컨트롤러, 서비스, 팩토리, 지시자 등이 종속되어 있기 때문에 더 그렇습니다.
그렇기 때문에 아래처럼 테스트 코드를 작성하기 전에 app을 먼저 읽어와서 설정을 해줘야합니다.
beforeEach(module('앱이름'));
컨트롤러 테스트 케이스 설정
다른 테스트 케이스들은 앱설정만 하면 어느정도의 테스트 케이스는 만들 수 있습니다.
하지만 컨트롤러의 테스트 케이스는 조금 다른 점이 있는데,
이 점은 컨트롤러가 DOM과의 연관성이 가장 높기 때문입니다.
그래서 컨트롤러의 테스트 케이스 설정방법은 조금 다릅니다.
beforeEach(inject(function ($controller, $rootScope) { // injector를 통해 $controller와 $rootScope를 inject받음
scope = $rootScope.$new(); // $rootScope.$new()를 위해 컨트롤러가 동작할 scope를 설정합니다.
ContainerCtrl = $controller('MyCtrl', { // MyCtrl의 컨트롤러를 $element와 $scope에 아래의 값을 넣어서 만듭니다.
$element : angular.element('<div/>'), // <div/>만 들어가 있는 DOM을 $element에 할당합니다.
$scope: scope // $scope에 목으로 만든 scope객체를 할당합니다.
});
}
위와 같은 형식으로 컨트롤러 테스트 케이스를 작성하는데,
이렇게 작성한 테스트 환경을 작동하면 실제 컨트롤러의 코드에서 scope를 접근하는 것을 mocking할 수 있고,
또한 컨트롤러가 선언된 DOM 트리를 지정해 줄 수 있습니다.
그리고 컨트롤러에서 $element를 사용한다면, 꼭 mocking을 해줘야 합니다.
$httpBackend
테스트를 하면 서버에 어떤 요청을 했는지 확인하고, 요청에 대한 응답을 정하고 싶을 때가 있습니다. 그 때에 사용하는 것이 $httpBackend입니다. 아래 내용은 공식홈페이지에 나와있는 $httpBackend에 관련된 내용입니다.
$http 서비스를 테스트할 때 사용합니다.
테스트하는 동안 서버에 XHR이나 JSONP가 요청되지 않기를 원합니다.
http를 테스트 하는데는 2가지 종류로 테스트가 가능합니다.
$httpBackend.expect: 정확한 request가 예상될때(해당 요청이 안와도 에러가 나옴)
$httpBackend.when: backend를 정의할 때(어떤 요청에 대해 어떤 답을 주라는 설정)
flush() 메소드를 실행하면 해당요청에 대한 설정한 반환값이 반환됩니다.
그리고 아래는 $httpBackend를 사용하는 예입니다.
// $httpBackend mock 설정 부분
$httpBackend.expectGET('test할 URL')
.respond({
기대하는 응답값
});
// 테스트 코드..
$httpBackend.flush(); // http요청에 대한 호출
$timeout
$timeout은 몇 ms 후에 코드를 실행시키게 하는 코드인데, 테스트를 할 때는 그 시간을 기다릴 필요가 없습니다.
그래서 $timeout을 테스트 하기 위해서는 $timeout의 안의 코드를 강제로 실행시켜야 합니다.
그 때에 아래처럼 실행 시킬 수 있습니다.
// 테스트 코드..
$timeout.flush();
$provide
테스트를 할 때에 controller에 들어가는 library 객체들을 수정하고 싶을 때가 있습니다.
그럴 때 사용하는 것이 $provider입니다.
$provide를 통해 해당 코드가 동작하는 환경을 변경할 수 있습니다.
사용방법은 아래와 같습니다.
beforeEach(mock(function($provide) {
$provider.value(...);
}));
$watch
$watch는 AngularJs에서 어떤 객체의 변화를 계속 확인하다가 그 값이 변경되면 다른 함수를 호출하는 것입니다.
$watch를 테스트 할 때는 scope에 $digest를 호출하는데 그렇게 되면 $watch로 확인하는 값이 변경되었는지 한번 더 확인합니다.
그러니 $watch로 감시하는 값을 변경시키고 $digest를 호출하면 해당 함수를 테스트할 수 있습니다.
$watch와 관련된 내용은 이 블로그에서 자세히 나옵니다.
$on
$on은 AngularJs에서 이벤트의 발생을 기다리다가 이벤트가 발생하면 다른 함수를 호출하는 역할을 합니다.
$on을 테스트 할 때는 $broadcast와 $emit을 통해서 이벤트를 강제로 발생시켜서 해당 함수를 테스트 할 수 있습니다.