AngularJS는 jQuery 이후 JavaScript에 일어난 가장 좋은 일입니다. 이것이 JavaScript 개발이 항상 의도했던 방식입니다. Angular의 주요 장점 중 하나는 종속성 주입(종속성 주입)으로, 이는 코드 단위 테스트에 매우 편리합니다. 그런데 조금 이상한 점은 단위 테스트를 수행하는 방법에 대한 튜토리얼을 찾을 수 없다는 것입니다.
물론 Jasmine 테스트 프레임워크와 Karma 테스트 실행기(Test Runner)를 사용하는 등 좋은 권장 사항이 많이 있지만 처음부터 테스트하는 방법에 대한 완전한 튜토리얼은 없습니다. 그래서 이 글을 썼습니다. 나는 그것을 수행하는 방법을 알아내기 위해 온라인에서 많은 리소스를 찾았으며 지금은 그 어떤 것도 수행할 필요가 없습니다(처음에 이 기사를 읽었다면).
이것이 Karma 및 Jasmine을 기반으로 하는 Angular 앱을 테스트하는 모범 사례라고 말할 수 있을 때까지 오류가 나타나면 알려주시기 바랍니다.
소개
이 문서에서는 자동화된 테스트를 위해 Karma와 Jasmine을 사용하는 데 필요한 모든 도구를 설치하는 방법을 안내합니다. 실제로 TDD(Test Driven Development)를 사용하든 TAD(Test Assisted Development)를 사용하든 상관없습니다. 이 기사에서는 테스트할 파일이 이미 있다고 가정합니다.
Karma 설치
Node.js가 설치되어 있지 않은 경우 직접 다운로드하여 설치하시기 바랍니다. 설치 후 터미널이나 명령줄을 열고 다음 명령을 입력하세요.
npm install -g karma
파일 구조
파일 구조는 우리 주제와 밀접한 관련은 없지만, 다음 테스트에서 제가 사용한 파일 구조는 다음과 같습니다.
Application | angular.js | angular-resource.js | Home | home.js | Tests | Home | home.tests.js | karma.config.js (will be created in the next step) | angular-mocks.js
*이 문서 구조를 옹호하는 것은 아니며 단지 테스트 예시로 보여드리는 것입니다.
Karma 구성
구성 파일을 저장할 디렉터리로 전환한 후 터미널에 다음 명령을 입력하여 구성 파일을 만듭니다.
karma init karma.config.js
사용하려는 테스트 프레임워크, 자동 모니터링 파일이 필요한지 여부, 어떤 테스트 및 테스트된 파일이 포함되어 있는지 등 몇 가지 질문을 받게 됩니다. 튜토리얼에서는 'Jasmine'을 기본 프레임워크로 유지하고 자동 파일 감지를 활성화하며 다음 파일을 포함합니다.
../*.js ../**.*.js angular-mocks.js **/*.tests.js
다음은 1) 상위 디렉터리에 있는 모든 .js 파일, 2) 상위 디렉터리 아래의 모든 하위 디렉터리에 있는 모든 .js 파일, 3) 현재 디렉터리에 있는 angle-mock.js, 4) 및 모든 항목을 포함한 상대 경로입니다. .tests.js 파일은 현재 디렉터리(하위 디렉터리 포함)에 있습니다(저는 이런 방식으로 테스트 파일을 다른 파일과 구별하는 것을 좋아합니다).
어떤 파일을 선택하든지 angle.js, angle-mock.js 및 사용해야 하는 기타 파일을 포함했는지 확인하세요.
카르마 시작
이제 Karma를 시작할 수 있습니다. 여전히 터미널에 입력하세요.
karma start karma.config.js
이 명령은 컴퓨터의 구성 파일에 나열된 브라우저를 실행합니다. 이러한 브라우저는 소켓을 통해 Karma 인스턴스에 연결되며 활성 브라우저 목록이 표시되고 테스트 실행 여부에 대한 알림을 받게 됩니다. Karma가 각 브라우저의 최종 테스트 결과 요약을 제공했으면 좋겠지만(예: 16개 중 15개 통과, 1개 실패) 안타깝게도 이 정보는 터미널 창을 통해서만 볼 수 있습니다.
Karma의 뛰어난 기능 중 하나는 네트워크의 모든 장치를 사용하여 코드를 연결하고 테스트할 수 있다는 것입니다. 모바일 브라우저에서 Karma 서비스를 지정해 보세요. 컴퓨터에서 실행되는 모든 브라우저에서 테스트 URL을 찾을 수 있습니다. http://localhost:9876/?id=5359192와 같아야 합니다. 휴대폰, 가상 머신 또는 기타 장치의 브라우저를 [네트워크의 IP 주소]:9876/?id=5359192로 지정할 수 있습니다. Karma는 Node.js 인스턴스를 실행하므로 테스트 머신은 웹과 같습니다. 서버를 가리키는 모든 브라우저로 테스트가 전송됩니다.
기본 테스트
테스트할 파일이 이미 있다고 가정합니다. 우리가 사용하려는 home.js 파일은 다음과 같습니다.
home.js
'use strict'; var app = angular.module('Application', ['ngResource']); app.factory('UserFactory', function($resource){ return $resource('Users/users.json') }); app.controller('MainCtrl', function($scope, UserFactory) { $scope.text = 'Hello World!'; $scope.users = UserFactory.get(); });
home.test.js 파일에서 테스트 케이스를 생성할 수 있습니다. 간단한 테스트부터 시작해 보겠습니다. $scope.text는 'Hello World!'와 같아야 합니다. 이 테스트를 완료하려면 애플리케이션 모듈과 $scope 변수를 모의해야 합니다. Jasmine의 beforeEach 메소드에서 이 작업을 수행하여 각 테스트 케이스 시작 시 완전히 새로운(깨끗한) 컨트롤러와 범위 객체를 갖게 됩니다.
home.tests.js
'use strict'; describe('MainCtrl', function(){ var scope; //我们会在测试中使用这个scope //模拟我们的Application模块并注入我们自己的依赖 beforeEach(angular.mock.module('Application')); //模拟Controller,并且包含 $rootScope 和 $controller beforeEach(angular.mock.inject(function($rootScope, $controller){ //创建一个空的 scope scope = $rootScope.$new(); //声明 Controller并且注入已创建的空的 scope $controller('MainCtrl', {$scope: scope}); }); // 测试从这里开始 });
코드 외부에서 정보의 유효성을 검사할 수 있도록 자체 범위를 삽입하는 것을 볼 수 있습니다. 또한, 모듈 자체를 모의하는 것을 잊지 마세요(라인 7)! 이제 테스트할 준비가 되었습니다.
home.tests.js
// 测试从这里开始 it('should have variable text = "Hello World!"', function(){ expect(scope.text).toBe('Hello World!); });
如果你运行这个测试,它可以在任何指向Karma的浏览器中执行,并且测试通过。
发送$resource请求
现在我们已经准备好测试 $resource 请求。要完成这个请求,我们需要使用到 $httpBackend, 它一个模拟版本的Angular $http。我们会创建另一个叫做 $httpBackend 的变量,在第二个 beforEach块中,注入 _$httpBackend_ 并将新创建的变量指向 _$httpBackend_。接下来我们会告诉 $httpBackend 如何对请求做出响应。
$httpBackend = _$httpBackend_; $httpBackend.when('GET', 'Users/users.json').respond([{id: 1, name: 'Bob'}, {id:2, name: 'Jane'}]);
我们的测试: home.tests.js
it('should fetch list of users', function(){ $httpBackend.flush(); expect(scope.users.length).toBe(2); expect(scope.users[0].name).toBe('Bob'); });
都放到一起
home.tests.js
'use strict'; describe('MainCtrl', function(){ var scope, $httpBackend; //we'll use these in our tests //mock Application to allow us to inject our own dependencies beforeEach(angular.mock.module('Application')); //mock the controller for the same reason and include $rootScope and $controller beforeEach(angular.mock.inject(function($rootScope, $controller, _$httpBackend_){ $httpBackend = _$httpBackend_; $httpBackend.when('GET', 'Users/users.json').respond([{id: 1, name: 'Bob'}, {id:2, name: 'Jane'}]); //create an empty scope scope = $rootScope.$new(); //declare the controller and inject our empty scope $controller('MainCtrl', {$scope: scope}); }); // tests start here it('should have variable text = "Hello World!"', function(){ expect(scope.text).toBe('Hello World!'); }); it('should fetch list of users', function(){ $httpBackend.flush(); expect(scope.users.length).toBe(2); expect(scope.users[0].name).toBe('Bob'); }); });
技巧
Karma会运行所有文件中的所有测试用例,如果你只想运行所有测试的一个子集,修改 describe 或 it 为 ddescribe 或 iit 来运行个别的一些测试。如果有些测试你不想运行他们,那么修改 describe 或 it 为 xdescribe 或 xit 来忽略这些代码。
你也可以在html文件的页面上运行你的测试。举例的代码如下:
home.runner.html
<!DOCTYPE html> <html> <head> <title>Partner Settings Test Suite</title> <!-- include your script files (notice that the jasmine source files have been added to the project) --> <script type="text/javascript" src="../jasmine/jasmine-1.3.1/jasmine.js"></script> <script type="text/javascript" src="../jasmine/jasmine-1.3.1/jasmine-html.js"></script> <script type="text/javascript" src="../angular-mocks.js"></script> <script type="text/javascript" src="home.tests.js"></script> <link rel="stylesheet" href="../jasmine/jasmine-1.3.1/jasmine.css"/> </head> <body> <!-- use Jasmine to run and display test results --> <script type="text/javascript"> var jasmineEnv = jasmine.getEnv(); jasmineEnv.addReporter(new jasmine.HtmlReporter()); jasmineEnv.execute(); </script> </body> </html>