본문 바로가기

FrontEnd+

cypress - stub 사용법, Alert 테스트 예제, 이벤트타입

'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 다른 링크로 제대로 이동하는지 테스트할 수 있다.  

 

 

 

참고자료

 

stub

Replace a function, record its usage and control its behavior. Note: .stub() assumes you are already familiar with our guide: Stubs, Spies, and Clocks Syntaxcy.stub() cy.stub(object, method) cy.stub(

docs.cypress.io

 

Stubs, Spies, and Clocks

What you’ll learn Which libraries Cypress includes to provide typical testing functionality How to use stubs for asserting that code was called but preventing it from executing How to use spies for a

docs.cypress.io

 

Catalog of Events

Cypress emits a series of events as it runs in your browser. These events are useful not only to control your application’s behavior, but also for debugging purposes. Here are some examples you can do

docs.cypress.io