AngularJS를 사용해서 구현한 Single Page Application(SPA)는 Unit Testing, End-to-end(E2E) Testing 2가지 방법을 이용해서 테스트가 가능하다.
- Unit Tesing:
karma
기반의jasmine/mocha
테스트 프레임워크 - E2E Testing:
Selenium WebDriver
로 브라우저 테스트 자동화,Protractor
프레임워크 기반으로 jasmine/mocha 테스트 프레임웍을 사용
karma, jasmine, mocha, protractor 모두 nodejs 기반으로 동작한다. E2E 테스트는 Protractor 기반으로 jasmine이나 mocha를 이용해서 테스트 코드를 작성하고, Selenium WebDriver가 브라우저를 자동 실행하여 화면 이벤트를 발생시킨다.
Unit Testing using Karma
카르마 설치하기
1 | # Install Karma: |
Karma 패키지
를 설치한다. jasmine 기반으로 테스트 하기 위해서 karme-jasmine
도 설치해준다. karma-chrome-launcher
은 필요없다면 굳이 설치하지 않아도 상관없다. 윈도우에서 사용하려면 karma-cli
를 설치하면 쉽게 사용할 수 있다고 한다. (근데 사용해보니 제대로 동작하지 않는 것 같음)
karma 설정하기
karma init 파일명.js
을 이용해서 카르마 설정 파일을 만들어 준다. 다음과 같이 커맨드 창에 입력하면, 문답형식으로 간단하게 설정 파일을 생성할 수 있다.
1 | $ karma init karma.conf.js |
생성된 karma.conf.js
을 개발 환경에 맞춰 수정하였다. 결과는 아래와 같다.
1 | module.exports = function(config) { |
karma start karma.conf.js
를 입력해서 유닛 테스트를 실행한다. Karma v0.13.22 server started at http://localhost:8080
이라는 로그가 뜨면 정상적으로 실행된 것이다. 브라우져로 크롬을 선언해주긴 했는데, 자동으로 실행되지 않는다. 아무 브라우저나 열고 http://localhost:8080
으로 접속하면 페이지에 karma v0.13.22 - connected
라고 떠있는걸 확인 할 수 있다. 추후에 테스트 코드를 작성하고 해당 페이지에 접속하면 로그 창에서 테스트의 성공/실패 여부를 확인 할 수 있다.
테스트 코드 작성하기
테스트를 진행하기 위해서 다음 3가지 파일을 생성한다. *Spec.js
파일은 테스트 코드이며, entpListTest.js
는 angular module이다.
- controllerSpec.js
- serviceSpec.js
- entpListTest.js
1 | // controllerSpec.js |
beforeEach()
메소드에서는 각 it
블록이 실행되기 전에 공통적으로 실행되어야 할 동작들을 선언한다. module
을 로딩하며, _$rootScope_
와 _$controller_
를 inject
를 통해서 주입받아 UserListCtrl
에 스코프 객체를 넘겨주어 it
블록에서 expect를 통해 EntpList을 검증한다. Angular에서는 service
에서 자료구조와 비즈니스 로직을 생성하고 controller
에서 service를 주입받아 사용한다.
EntpService에서는 매장 목록을 조회하고, 매장을 추가하고, 삭제할 수 있다.
1 | // serviceSpec.js |
다음은 entpListTest
애플리케이션 소스 코드이다.
1 | // entpListTest |
*Spec.js
파일을 먼저 생성하여, controller와 service에 필요한 기능들을 정의한다. 테스트 코드에 맞게 애플리케이션을 수정할 때 마다, 자동으로 karma가 갱신되면서 테스트를 수행한다. 애플리케이션이 올바르게 작성될 때까지 로그에는 테스트가 실패했다는 에러 문구가 뜬다. success
가 뜰때까지 하나씩 지워나가면 된다.
E2E Testing using Protractor
예전부터 브라우저 기반으로 애플리케이션을 테으스트 하기 위한 시도가 있었고, 셀리넘과 웹드라이버가 따로 있었으나 현재는 셀레니엄 버전 2.0에서 셀레니엄과 웹드라이버의 각 장점을 취해 셀리니엄 웹드라이버라는 이름으로 발전했다. Angular Protractor
는 셀레니엄 웹드라이버를 기반으로 애플리케이션 UI를 테스트 하기 위해 브라우저를 자동으로 기동해 테스트를 수행하는 E2E 테스트 프레임워크이다.
준비하기
Protractor
는 Node.js
프로그램이다. Protractor를 사용하기 위해서는 사전에 Node.js가 설치되어 있어야 하며, v0.10.0 이상의 Node.js를 필요로 한다. node --version
을 통해서 현재 Node.js의 버전을 확인할 수 있다. 기본적으로 Protractor는 Jasmine
을 사용하기 때문에, Jasmine 또한 기본적으로 설치 되어 있어야 한다.
Protractor 설치하기
-g
옵션을 줘서 글로벌로 protractor를 설치한다. local로 설치해봤는데 잘 안돌아가는데 이유는 잘 모르겠다.
1 | # protractor와 webdriver-manager를 설치한다. |
protractor를 설치하면 기본적으로 webdriver-manager를 자동으로 설치해주지만, 크롬 브라우저에서 자동화 테스트를 수행하는 ChromeDriver
를 추가 설치 하기 위해서 webdriver-manager를 update 한다. 아래와 같은 오류가 발생한다면 JDK 버전을 확인하여 버전을 맞춰준다.
1 | Exception in thread "main" java.lang.UnsupportedClassVersionError: org/openqa/grid/selenium/GridLauncher : Unsupported major.minor version 51.0 |
webdirver-manager
가 정상적으로 실행되면 RemoteWebDriver 인스턴스가 http://127.0.0.1:44/wd/hub
와 연결되었고, Selenium Server
가 구동 중이라는 로그를 확인 할 수 있다.
테스트 코드 작성하기
애플리케이션 화면 테스트에는 페이지 오브젝트 디자인 패턴(Page Object Design Pattern)
방식이 사용되곤 하는데, 이 방식을 사용하면 중복 코딩을 방지하고 페이지 오브젝트를 이용해 재사용 가능한 테스트를 수행할 수 있다. 또한 UI가 변경됐을 떄 테스트 코드는 그대로 두고 페이지 오브젝트만 변경하는 방식을 취할 수 있어 변화에 대한 유지보수를 수월하게 해준다. 먼저 화면에 대한 페이지 오브젝트를 정의한 후에 페이지 오브젝트를 사용해 테스트 코드를 정의해야 한다. Protractor는 페이지 오브젝트를 작성하기 위해서 몇가지 전역변수를 사용한다.
browser
: 웹드라이버의 인스턴스로 페이지를 네비게이션한다.element
: 테스트하려는 페이지의 엘리먼트를 찾고 상호작용 해주는 도움 함수이다.ElementFinder
객체를 반환한다.element(by.css('my-css'))
는$('my-css')
와 동일한 의미라고 생각하면 된다.
by
: 엘리먼트를 찾을 수 있는 로케이터의 컬렉션으로CSS, ID, ng-bind
등을 찾을 수 있다.<div ng-model="todo"/>
는by.model("todo")
로 찾는다.<div>{angular 표현식}</div>
는by.binding("todo")
로 찾는다.<div ng-repeat="todo in todos">
는by.repeater("todo in todos").row(1)
로 두번재 todo 객체를 찾을 수 있다.
Step 0 - write a test
Protractor를 구동시키기 위해서는 기본적으로 spec file
과 configuration file
이 필요하다. 테스팅을 위해서 Super Calculator를 사용할 것이며, 소스 코드는 별도로 정리해두었다.
1 | // spec.js |
describe
와 it
syntax는 Jasmine에서 가져온 것이다.
1 | // conf.js |
$ protractor conf.js
명령어를 통해서 테스트를 실시한다. 크롬브라우저가 잠깐 뜬 다음에 뭔가 쓱 지나간다. 다음과 같은 로그가 뜬다면 정상적으로 테스트가 진행된 것이다.
1 | Started |
step 1 - interacting with elements
spec.js
의 내용을 다음과 같이 추가해준다.
1 | // spec.js |
sendkey
는 <input>
에 값을 넣기 위해서 사용되었으며, click
은 버튼을 클릭하기 위해서, getText
는 해당 엘리먼트의 텍스트를 가져오기 위해서 사용했다. by.id
는 id 값으로 엘리먼트를 사용하는데 사용된다. (by.model
, by.binding
은 앞서 설명했다) by.id('gobutton')
은 <button id="gobutton">
을 찾는다.
1 | Started |
위의 spec.js
는 테스트를 통과하지 못한다. 소스 코드를 수정해서 테스트를 통과시키면 된다.
step 2 - writing multiple scenarios
앞선 spec.js
는 테스트 케이스가 1개 만 존재한다. spec.js
파일을 수정해서 한번에 2개의 테스트를 수행해보자.
1 | // spec.js |
beforeEach
함수가 추가되었다. 해당 함수는 모든 it
블록이 실행되기 전에 공통적으로 수행되어야 할 작업을 선언하는데 사용된다. 위의 spec.js
를 테스트 하면 테스트는 통과되지 않는다. 수정해서 동작하게 만든다.
step 4 - lists of elements
list의 여러 엘리멘트를 다루기 위해서 element.all
을 사용한다. element.all
은 ElementArrayFinder
를 반환한다. spec.js
는 아래와 같이 수정한다.
1 | // spec.js |
ElementArrayFinder
를 얻기 위해서 by.repeater
와 element.all
을 함께 사용했다. history
의 크기를 측정하기 위해서 count
메소드를 사용했다. ElementArrayFinder
는 count
이외에도 다양한 메소드를 제공한다. last
는 Locator에 의해서 찾을 수 있는 엘리멘트의 마지막 값을 얻는데 사용할 수 있다. each
, map
, filter
, reduce
등도 사용될 수 있다. 자세한 건 API 문서를 확인하면 된다.
1 | it('should have a history', function() { |
틀린 부분을 통과 시키도록 구현하면 된다.
Reference
- http://karma-runner.github.io/0.13/intro/installation.html
- http://angular.github.io/protractor/#/tutorial
- http://juliemr.github.io/protractor-demo/
- http://stackoverflow.com/questions/32282801/unable-to-run-selenium-standalone-server
- http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
- https://en.wikipedia.org/wiki/Java_class_file
Comments