Jello's development blog

Jello's development blog

Karma, Jasmine을 이용한 AngularJs 테스트

들어가며

내게 AngularJs는 처음으로 접한 프레임워크라서 상대적으로 시야가 좁은 상태에서 공부를 했고, 테스트라는 것 또한 모르는 상태로 개발했었다. 시간이 꽤 지난 지금 AngularJs를 다시 보니 예전에 놓친것들이 많다고 느껴서, Karma와 Jasmine을 이용하여 테스트하는 법을 포스팅하려고 한다. 포스팅에 사용된 Repository의 주소는 https://github.com/guswnsxodlf/angularjs-test이다.

karma는 무엇인가?

karma github repository를 보면 여러 실제 브라우저에 Javascript를 실행시킬 수 있게 해주는 간단한 도구라고 되어있다. 따라서 Javascript를 실행만 시켜주는 도구이므로 여기에 Jasmine이나 Mocha, QUnit같은 테스트 프레임워크를 붙여서 사용하는 것이다. 초반에는 Testacular라는 이름이었지만, 후에 Karma라는 이름으로 변경되었다.

npm로 테스트 package 설치, karma 설정

npm init을 이용하여 package.json을 생성해준다. 명령어를 입력하면 나오는 여러 질문에 알맞게 입력하여 대답해주자.

$ npm init

그 뒤에, 테스트를 하기 위해서 karma, jasmine 관련 필요한 package들을 설치한다.

$ npm install jasmine-core --save-dev
$ npm install karma, karma-chrome-launcher, karma-jasmine --save-dev

이를 끝낸 뒤에 프로젝트 디렉토리에 생성된 package.json다음과 같다. 따라할 때 각 package의 버전이 다를 수 있으니 주의하도록 한다.

이제 karma를 설정할 차례이다. 먼저 전역으로 karma-cli를 설치한다.

$ npm install -g karma-cli

karma로 테스트 코드를 실행시키기 위해서는 설정파일이 필요하다. 아래 명령어를 입력하여 karma.conf.js파일을 생성한다.

$ karma init karma.conf.js

명령어를 입력하면 아래 질문들이 나오는데, 상황에 맞게 적절하게 입력하면 된다. 현재 이 글에서는 jasmine을 사용하고 chrome으로 테스트할 것이므로 아래처럼 입력한다.

which testing framework do you want to use ?
(어떤 테스팅 프레임워크를 사용할 것인가?)
Press tab to list possible options. Enter to move to the next question.
> jasmine

Do you want to use Require.js ?
(Require.js 를 사용할 것인가?)
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no

Do you want to capture any browsers automatically ?
(어떤 브라우저 환경에서 테스트할 것인가?)
Press tab to list possible options. Enter empty string to move to the next     question.
> Chrome
>

What is the location of your source and test files ?
(테스트 대상과 테스트 스펙 파일에 대한 위치)
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> 

Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
(테스트할 파일들중 제외할 파일들에 대한 패턴)
Enter empty string to move to the next question.
>

Do you want Karma to watch all the files and run the tests on change ?
(파일이 변경되었을 때 자동으로 테스트를 실행할 것인가?)
Press tab to list possible options.
> yes

이를 완료하면 설정 파일이 만들어진다. karma를 실행시켜서 있지도 않은 테스트가 통과하는지 확인해보자.

$ karma start

karma.conf.js파일에 테스트 대상을 설정해주지 않았기 때문에 에러가 발생한다. 이는 지극히 정상적이고 예측된 결과이니 신경쓰지 말고 넘어가도록 하자. 글의 후반부에서 다시 다루도록 하겠다.

bower로 front-end package 설치

front-end package를 관리하기 위해서 bower를 사용한다.
먼저 아래 명령어를 입력하여 bower를 전역으로 설치한다. 이미 설치되어 있다면 건너뛰어도 좋다.

$ npm install -g bower

bower를 설치한 뒤에, angular, angular-mocks를 설치한다.
angular-mocks는 테스트를 할 때 필요한 package이다.

$ bower init
$ bower install --save angular
$ bower install --save-dev angular-mocks

이를 끝낸 뒤에 프로젝트 디렉토리에 생성된 bower.json다음과 같다. 따라할 때 버전이 다를 수 있으니 주의하도록 한다.

Angular 모듈, 컨트롤러 생성

이제 본격적으로 프로젝트 파일을 만들어 보도록 하자. app/src/app.js에 모듈을 생성해주고, 모듈 의존성을 명시해준다.

app/src/app.js

angular.module('test', [
    'test.controller'
]);

angular.module('test.controller', []);

가장 크고 프로젝트를 감싸주는 모듈의 이름을 test로 했고, 컨트롤러를 걸어줄 모듈의 이름은 test.controller으로 한 뒤에 test모듈에서 사용할 수 있도록 하였다.

이제 test.controller모듈에 MainCtrl컨트롤러를 생성해보자.

app/src/controller/MainCtrl.js

angular.module('test.controller').controller('MainCtrl', ['$scope', function($scope){
    $scope.test = "Hello Test!";
}]);

간단하게 test변수의 값을 Hello Test!로 설정해주었다.

테스트코드 생성

Angualr 모듈과 컨트롤러를 아주 간단하게 만들었으니 이제 그것을 확인할 테스트 코드를 작성해보자. testController.js파일을 다음과 같이 생성한다.

app/src/test/testController.js

describe("컨트롤러 테스트", function(){
    beforeEach(module('test.controller'));

    var $controller;
    beforeEach(inject(function(_$controller_){
        $controller = _$controller_;
    }));

    describe('MainCtrl', function() {
        it('MainCtrl이 정의되어 있다', function(){
            var $scope = {};
            var MainCtrl = $controller('MainCtrl', { $scope: $scope });
            expect(MainCtrl).toBeDefined();
            expect($scope.test).toEqual("Hello Test!");
        });
    });
});

제일 먼저 beforeEach함수로 테스트에 사용할 모듈을 로드한다. 그리고 난 뒤에 inject함수로 test.controller모듈 내의 컨트롤러를 불러올 수 있는 $controller를 가져온다. 그 뒤에, MainCtrl을 불러와서 정의되었는지, test변수가 Hello Test!인지 테스트한다.

inject함수는 angualr-mocks(ngMocks)의 함수인데, 이 부분이 이해가 어려운 부분인 것 같다. Docs에 나와있는 예제를 여러 번 숙지해야겠다.

karma.conf.js 수정

Angular 코드도 작성했고, 테스트 코드도 작성했으니 모두 다 한 것 같지만, 마지막으로 수정해야 할 부분이 남아있다. 아까 에러를 내고 수정하지 않았던 karma.conf.js파일이다.

karma.conf.js

...

files: [
    'bower_components/angular/angular.js',
    'bower_components/angular-mocks/angular-mocks.js',
    'app/src/app.js',
    'app/src/controller/MainCtrl.js',
    'app/src/test/test*.js'
],

...

fileskarma가 실행될 때 로드되는 파일의 path를 가지고 있는 배열이다. 이곳이 비어있었기 때문에 어떠한 것도 읽어들이지 않았고, 테스트가 실행되지 않은 것이다. 마지막 요소에서 test*.js는, test로 시작하는 javascript파일을 모두 로드하겠다는 의미이다.

이제 테스트를 실행해보자.

$ karma start

00 00 2016 00:00:00:WARN [karma]: No captured browser, open http://localhost:9876/
00 00 2016 00:00:00:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
00 00 2016 00:00:00:INFO [launcher]: Launching browser Chrome with unlimited concurrency
00 00 2016 00:00:00:INFO [launcher]: Starting browser Chrome
00 00 2016 00:00:00:INFO [Chrome 53.0.2785 (Mac OS X 10.11.6)]: Connected on socket /#xxxxxxxxxxxxxxxxx with id xxxxxxxx
Chrome 53.0.2785 (Mac OS X 10.11.6): Executed 1 of 1 SUCCESS (0.036 secs / 0.028 secs)

마침내 테스트가 성공했다는 로그를 볼 수 있으며 chrome 브라우저가 실행되면서 다음과 같은 창이 뜬다.

karma 실행 창

참고 링크