'stub' 란?
cypress에서 'stub'는 함수가 어떻게 사용되었는지 기록하고 프로그래머가 '함수의 동작을 컨트롤' 할 수 있게 해 준다.
영단어 'stub'는 '그루터기(초목을 베고 남은 밑동)' 또는 '뿌리째 뽑아낸다'는 뜻이다.
비슷한 기능을 가진 'spy'가 스파이처럼 기존 함수를 건드리지 않고 정보만 전달하는 반면, 'stub'는 프로그래머 마음대로 무엇이든 할 수 있도록 통째로 뽑아왔다는 의미에서 'stub'로 지은 게 아닐까 싶다.
'stub'는 유닛 테스트에 가장 흔하게 사용되지만 통합 테스트나 E2E 테스트에서도 유용하다.
stub 간단 사용법
stub는 cy.stub() 와 같이 cy 뒤에 체이닝 해서 사용한다.
리턴값이 체이닝 가능한 객체가 아니라 stub이기 때문에 stub 뒤에는 다른 assertion 구문을 체이닝 할 수 없다.
cypress의 다른 명령어와 달리 cy.stub()는 동기적이고 타임아웃되지 않는다.
stub는 다음과 같이 독립적으로 생성할 수도 있고, 객체와 그 객체의 메서드를 지정해서 사용할 수도 있다. 이 때, 인자를 지정하거나 리턴값을 지정할 수도 있다.
// 독립적인 stub를 생성한다. (보통 유닛테스트에 사용)
cy.stub()
// obj.method()를 stub화 한다.
cy.stub(obj, 'method')
// obj.method()가 "woowa"를 반환하도록 한다.
cy.stub(obj, 'method').returns('woowa')
// obj.method()가 'haru'인자와 함께 호출되었을 때 "woowa"를 반환하도록 한다.
cy.stub(obj, 'method').withArgs('haru').returns('woowa')
예를 들어 stub화 시킨 메서드(stubbed method)의 리턴값 지정하고 싶다면 아래와 같이 사용하면 된다.
// 앱이 시작되면 util.addListeners()가 호출되고 이 함수가 리스너를 삭제하는 함수를 리턴하는지 테스트한다.
const removeStub = cy.stub()
cy.stub(util, 'addListeners').returns(removeStub)
App.start()
App.stop()
expect(removeStub).to.be.called
Alert 테스트 예제
// 앱 코드
$('button').on('click', (e) => {
alert('woowa')
alert('tech')
alert('course')
})
// 테스트 코드
it('can assert on the alert text content', () => {
const alertStub = cy.stub()
cy.on('window:alert', alertStub)
cy
.get('button').click()
.then(() => {
expect(alertStub.getCall(0)).to.be.calledWith('woowa')
expect(alertStub.getCall(1)).to.be.calledWith('tech')
expect(alertStub.getCall(2)).to.be.calledWith('course')
})
})
독립적으로 생성한 stub에 alertStub라는 이름을 붙이고, 여기에 on메서드를 사용해서 alert 이벤트를 연결해준다.
버튼을 클릭한 후, then으로 이어받아 테스트를 진행한다.
alertStub뒤에 체이닝 되어있는 getCall(n)은 n번째 콜을 반환해준다. 각각의 콜을 접근할 수 있기 때문에 테스트가 용이하다.
to.be.calledWith 는 cy.stub()나 cy.spy()의 체이닝 해서 쓸 수 있는 assertion 구문으로, 예제처럼 사용하면 Alert 메세지 문구를 체크할 수 있다.
// 테스트 코드
it('can assert on the alert text content', () => {
const alertStub = cy.stub()
cy.on('window:alert', alertStub)
cy
.get('button').click()
.then(() => {
const actualMessage = alertStub.getCall(0).lastArg;
expect(actualMessage).to.equal(EXPECTED_ALERT_MESSAGE);
})
})
to.be.calledWith() 를 사용하지 않고 위와 같이 메세지의 텍스트를 to.eqaul()로 비교하는 방법도 있다.
이벤트 타입 & on 메서드
cy.on()을 사용하면 다양한 이벤트 상황을 테스트할 수 있다. 다음은 cy.on()과 함께 사용할 수 있는 이벤트 타입을 정리한 표이다.
이벤트 타입 | 활용 예시 | 비고 |
window:alert | Alert 메세지가 제대로 뜨는지 테스트할 수 있다. | Alert창은 무조건 자동으로 수락된다. (변경 불가) |
window:confirm | Confirm 메세지가 제대로 뜨는지 테스트할 수 있다. | '확인'을 누를지 '취소'를 누를지 선택할 수 있다. |
uncaught:exception | 에러가 발생하는지 테스트할 수 있다. | error 객체를 반환한다. |
window:before:load | 문서가 로드되기 시작했지만 자바스크립트는 실행되기 전에 필요한 내용을 테스트할 수 있다. | |
window:load | 모든 리소스가 로드된 후에 필요한 내용을 테스트할 수 있다. | |
window:before:unload | 페이지를 나가려고 할 때 필요한 내용을 테스트할 수 있다. | |
window:unload | 페이지를 실제로 나갔을 때 필요한 내용을 테스트할 수 있다. | 이 이벤트 취소할 수 없다. |
url:changed | 다른 링크로 제대로 이동하는지 테스트할 수 있다. |
참고자료
'FrontEnd+' 카테고리의 다른 글
[React] 공식문서로 시작하는 리액트 입문 1편 (5) | 2021.04.04 |
---|---|
웹팩(Webpack) 밑바닥부터 설정하기 (3) | 2021.03.23 |
쉽게 쓰인 유튜브 API 튜토리얼 (3) | 2021.03.07 |
cypress - 테스트 주도 개발(TDD, BDD) 적용 (4) | 2021.02.03 |
네트워크 면접질문 총정리 (1) | 2021.01.27 |