Knowledge Map
AngularJS UnitTest - Karma 본문
참고사이트
http://bendetat.com/karma-and-mocha-for-angular-testing.html
http://webframeworks.kr/tutorials/angularjs/angularjs_unit_test/
AngularJS 관련 스터디를 준비하면서 Unit Test 대목이 나왔다. 참고해라고 줬던 책이 출판되어 나온지 2,3년이 지났기 때문에 지금의 Angular, Karma, Jasmine, Mocha와 버전이 많이 달랐다. 당연히 책대로 하니까 잘 안되었고 할수 없이 인터넷에서 최대한 찾아볼수밖에 없었는데 그게 참 시행착오를 많이 겪은거 같다.
일단 Unit 테스트를 위해서 사용한 것은 AngularJS, Mocha, Chai, Karma, PhantomJS 였다.
Jasmine은 이상하게 안되는게 너무 많아서 어쩔수 없이 걍 안했다. 마음에 들게 성공된 방식은 Mocha를 이용했을 때 였다.
먼저 간단하게 Angular 프로젝트를 제네레이터로 셋팅해준다.
위의 화면은 CMD로 실행을 했으나 명령어에 NPM을 써넣어서 CMD내에서 NPM이 실행되면서 상단에 NPM이라고 뜨는거니까 혼란이 없도록 한다.
unitTest폴더안에서 Angular제네레이터를 실행해서 셋팅해주고 있다.
카르마 커맨드라인 인터페이스를 설치한다.
npm install -g karma-cli
카르마를 적용할 프로젝트에 위치하여 다음을 입력한다.
npm install --save-dev karma
npm install --save-dev karma-mocha
npm install --save-dev karma-phantomjs-launcher
npm install --save-dev karma-chai
만약 자스민을 사용할 경우
npm install
grunt-karma karma karma-jasmine jasmine-core--save-dev
npm
실행장면중 일부이다. 저렇게 깔다보면 간혹 빨간 글씨로 UNMET PEER DEPENDENCY mocha@* 이런식으로 여러개가 뜰 수 있다.
그럴때는 그냥 UNMET PEER DEPENDENCY 바로 뒤에 있는 것들을 npm install mocha --save-dev 이런식으로 다시 입력해 주면 해당 문제가 해결이 된다.
아마도 제대로 연결이 되지 않아서 그런거 같다.
이렇게 설치를 하고나면 간단하게 karma 설정을 할 수 있다.
karma init
1. 사용할 프레임 워크가 무엇입니까?
2. RequireJS를 사용하시겠습니까?
3. 어떤 브라우저 사용하시겠습니까?
4. 테스트할 파일, 위치는 무엇입니까?
5. 제외할 파일은 무엇입니까?
6. 바뀔때마다 테스트 런 하시겠습니까?
위의 물음에 대해서 저렇게 답하고 나서 걍 파일 들어가서 설정하는게 마음이 더 편했다.
저렇게 하면 karma.conf.js 라고 파일에 그 결과가 반영된다.
이것을 이제 서브라임, note++, 그외 IDE로 연다.
frameworks: ['mocha', 'chai'],
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'test/**/*.js',
'test/*.js'
],
위의 항목들을 위와 같이 바꾼다.
맨위의 것은 테스트 프레임워크, 밑의 것은 참고할 파일과 테스트 파일들이다. test/**/*.js 는 test 하위 디렉토리 안의 모든 js 파일들을 검사하겠다는 뜻이다.
우리가 테스트코드를 작성하고 나서 그것을 시험할 때, 그것들을 실행할수 있도록 지정하는 곳도 바로 여기서 하는 것이다.
여기서 수동으로 지정해주고 karma start를 하면 작동하면서 unit test를 할수 있게 되는 것이다.
아마 test 폴더 아래에 spec폴더가 있고 그 안에 파일이 2개 있을텐데 참고한 예제는 그 2개 파일을 쓰지 않기 떄문에 위의 'test/**/*.js'는 제외하기로 한다.
그리고 test 폴더안에 2개의 파일을 작성한다.
MyController.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | (function(){ angular.module('my-module', []); angular .module('my-module') .controller('MyController', [ '$scope','$http', function($scope, $http){ var self = this; self.firstName = ''; self.lastName = ''; self.getFullName = function(){ return self.firstName + ' ' + self.lastName; }; $scope.songs = [ 'Here Comes The Sun' ]; $scope.addSong = function(song){ $scope.songs.push(song); } $scope.instruments = ['foo']; $scope.status = ''; $http.get('api/get-instruments') .success(function(data){ $scope.instruments = data; }) .error(function(e) { $scope.status = 'ERROR'; }); console.log(self); return self; } ]); })(); | cs |
MyControllerTest.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | describe('MyController', function(){ beforeEach(module('my-module')); describe('!!!!!!!getFullName()!!!!!!!', function(){ it('\n=========should handle names correctly======', inject(function($controller){ // var myController = $controller('MyController'); var myController = $controller('MyController',{$scope:{}});; myController.firstName = 'George'; myController.lastName = 'Harrison'; myController.getFullName().should.equal('George Harrison'); console.log(myController.getFullName()); })); }); describe('!!!!!!addSong()!!!!!!!!!!', function(){ it('\n _____________should add songs_______________', inject(function($controller) { var scope = {}; var myController = $controller('MyController', { $scope: scope }); scope.addSong('While My Guitar Gently Weeps'); scope.songs.should.contain('While My Guitar Gently Weeps'); console.log(scope); })); }); describe('------------get-instruments result--------', function(){ it('--------should be added to scope--------',inject(function($controller, $httpBackend){ var scope = {}; $httpBackend.when('GET', 'api/get-instruments') .respond([ 'vocals', 'guitar', 'sitar' ]); var myController = $controller('MyController', { $scope:scope }); $httpBackend.flush(); scope.instruments.should.contain('guitar'); console.log(scope); })); describe('@@@@@@@@get-instruments with error@@@@@@@@@@', function(){ it('@@@@@@should have a status with error@@@@@@@', inject(function($controller, $httpBackend){ var scope = {}; $httpBackend .when('GET', 'api/get-instruments') .respond(500, ''); var myController = $controller('MyController', { $scope: scope }); $httpBackend.flush(); scope.status.should.equal('ERROR'); })); }); }); }); | cs |
MyController.js 파일을 테스트하는 MyControllerTest.js파일이다.
다시 test폴더 상위 폴더인 unitTest로 와서 Karma start를 하면 실행이 될 것이다.
다만 안되는 경우가 있다.
먼저 test폴더 또는 spec폴더 안에 karma.conf.js파일이 있을수 있다. 이러한 경우에는 그 파일도 실행이 되기 때문에 실행하다가 오류가 날수 있다.
그러니 왠만하면 karma.conf.js파일은 하나만 해놓는게 좋다.
또 하나는 karma 설정에서 테스트하려는 파일보다 angular.js 파일이 위에 있어야 한다는 것이다.
만약 순서가 바뀌어서 테스트 파일이 먼저 위에 있을 경우에는 테스트 파일이 실행되면서 angularjs의 모듈이 없다는 에러메세지가 뜬다.
이것은 angularjs가 실행되지 않았기 때문에 생기는 일이다.
따라서 설정파일에서는 왠만하면 angularjs는 가장 위에 놓자.
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'test/*.js'
],
scope를 고쳐서 에러를 일부러 발생시켜보면 이렇게 출력이 된다.
'WEB' 카테고리의 다른 글
AngularJS ng-repeat & ng-if (0) | 2016.03.16 |
---|---|
UDP (0) | 2016.03.08 |
addEventListener, 미디어쿼리 (1) | 2016.02.27 |
AngularJS에서 carousel 적용하기 (0) | 2016.02.24 |
20160223 (0) | 2016.02.23 |