GitLab CI/CD와 WebdriverIO를 사용한 엔드 투 엔드 테스트

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

리뷰 앱은 훌륭합니다: 모든 병합 요청(또는 브랜치에도 해당)마다 새로운 코드를 복사하여 신선한 프로덕션 유사 라이브 환경에 배포할 수 있어 변경 사항의 영향을 평가하는 수고를 줄일 수 있습니다. 따라서 Dependencies.io와 같은 종속성 관리자를 사용할 때, 업데이트된 종속성을 가지고 병합 요청을 제출할 수 있으며, 애플리케이션이 여전히 적절하게 빌드되고 배포될 수 있음을 즉시 명확하게 알 수 있습니다. 결국, 실행 중인 것을 볼 수 있으니까요!

dependencies.io

그러나 새로 배포된 코드를 살펴보며 여전히 예상대로 보이고 작동하는지 확인하는 것은 반복적인 수동 작업으로, 이는 자동화의 주요 후보입니다. 여기서 자동화된 엔드 투 엔드 테스트가 필요합니다: 모든 레이어의 적절한 기능을 요구하는 몇 가지 간단한 시나리오를 컴퓨터가 실행하도록 하는 것입니다. 프론트엔드에서 데이터베이스까지 말이죠.

이 글에서는 그러한 엔드 투 엔드 테스트를 작성하는 방법과 GitLab CI/CD를 설정하여 새로운 코드에 대해 이 테스트를 자동으로 실행하는 방법을 설명하겠습니다. 이 글의 범위에서는 WebdriverIO를 사용하여 JavaScript 기반 애플리케이션의 엔드 투 엔드 테스트를 위해 GitLab CI/CD를 설정하는 과정을 안내할 것이지만, 일반적인 전략은 다른 언어에도 잘 적용될 것입니다.

우리는 여러분이 GitLab, GitLab CI/CD, 리뷰 앱 및 로컬에서 애플리케이션을 실행하는 방법(예: localhost:8000)에 익숙하다고 가정합니다.

무엇을 테스트할 것인가

널리 사용되는 테스트 피라미드 전략에서 엔드 투 엔드 테스트는 감독자 역할을 합니다: 코드의 대부분은 문제 발생 시 쉽게 원인을 식별할 수 있도록 하는 단위 테스트로 커버되어야 합니다. 실제로는 배포가 의도대로 진행되었는지, 인프라가 정상적으로 운영되고 있는지, 코드 조각들이 잘 협력하는지를 확신할 수 있을 만큼만 엔드 투 엔드 테스트의 수를 제한하는 것이 좋습니다.

Selenium과 WebdriverIO

Selenium은 웹 브라우저를 제어할 수 있는 소프트웨어로, 예를 들어 특정 URL을 방문하거나 페이지의 요소와 상호작용하기 위해 사용됩니다. 다양한 프로그래밍 언어에서 프로그래밍적으로 제어할 수 있습니다. 이 글에서는 WebdriverIO JavaScript 바인딩을 사용할 예정이지만, 일반적인 개념은 Selenium에서 지원하는 다른 프로그래밍 언어에도 잘 적용될 것입니다.

테스트 작성하기

WebdriverIO에서 지원하는 여러 테스트 프레임워크를 사용하여 테스트를 작성할 수 있습니다. 여기서는 Jasmine를 사용할 것입니다:

describe('계정이 없는 방문자', function(){
    it('404 페이지에서 홈페이지로 이동할 수 있어야 합니다', function(){
        browser.url('/page-that-does-not-exist');

        expect(browser.getUrl()).toMatch('page-that-does-not-exist');

        browser.element('.content a[href="/"]').click();

        expect(browser.getUrl()).not.toMatch('page-that-does-not-exist');
    });
});

함수 describe, it, 그리고 browser는 WebdriverIO에서 제공됩니다. 하나씩 살펴보겠습니다.

함수 describe는 관련 테스트를 그룹화할 수 있게 해줍니다. 이는 여러 테스트에 대해 동일한 초기화 명령을 실행하고 싶을 때 유용합니다(예: beforeEach를 사용하여 로그인 상태를 확인하는 경우).

함수 it는 개별 테스트를 정의합니다.

빠른 테스트를 제공하는 browser 객체는 WebdriverIO의 핵심입니다. 이는 브라우저를 조종하는 데 필요한 WebdriverIO API 메서드의 대부분을 제공합니다. 이 경우, /page-that-does-not-exist를 방문하여 404 페이지에 접근하기 위해 browser.url을 사용할 수 있습니다. 그런 다음 browser.getUrl을 사용하여 현재 페이지가 우리가 지정한 위치에 있는지 확인할 수 있습니다. 페이지와 상호작용하기 위해 CSS 선택자를 browser.element에 전달하여 페이지의 요소에 접근하고 상호작용할 수 있습니다 - 예를 들어, 홈페이지로 돌아가는 링크를 선택하는 것입니다.

위에 보여진 간단한 테스트는 통과하면 많은 자신감을 줄 수 있습니다: 배포가 성공했음을 알고, 페이지의 요소들이 보이며 실제 브라우저가 이를 상호작용할 수 있음을 알고 있으며, 라우팅이 예상대로 작동함을 알 수 있습니다. 그 모든 것이 10줄의 과도한 공백으로 이루어져 있습니다! 여기에 성공적인 단위 테스트와 성공적으로 완료된 파이프라인이 추가되면, 종속성 업그레이드로 인해 아무것도 손상되지 않았음을 상당히 확신할 수 있습니다.

로컬에서 실행하기

우리는 CI/CD에서 위의 테스트를 실행하는 방법을 곧 알아볼 것입니다. 그러나 테스트를 작성할 때,

파이프라인이 성공할 때까지 기다릴 필요 없이 그들이 기대하는 대로 작동하는지 확인할 수 있다면 도움이 됩니다.

다시 말해, 로컬에서 실행할 수 있도록 해보겠습니다.

귀하의 애플리케이션이 로컬에서 실행되고 있는지 확인하십시오. Webpack을 사용하는 경우,

테스트를 실행하기 전에 자동으로 개발 서버를 시작하는 Webpack Dev Server WebdriverIO 플러그인을 사용할 수 있습니다.

WebdriverIO 문서는 모든 구성 옵션에 대한 개요를 제공하지만,

시작하는 가장 쉬운 방법은 WebdriverIO의 기본 구성으로 시작하는 것입니다.

이는 모든 사용 가능한 옵션에 대한 개요를 제공합니다. 현재 가장 관련 있는 두 가지 옵션은 테스트 경로에 대한 배열인 specs 옵션과 애플리케이션이 실행되고 있는 위치를 가리키는 baseUrl 옵션입니다. 그리고 마지막으로, WebdriverIO에게 테스트를 실행하고자 하는 브라우저를 알려야 합니다.

이는 브라우저 이름의 배열(예: firefox거나 chrome)을 통해 capabilities 옵션으로 구성할 수 있습니다.

모든 설치된 브라우저를 감지하기 위해 selenium-assistant를 설치하는 것이 좋습니다:

  const seleniumAssistant = require('selenium-assistant');
  const browsers = seleniumAssistant.getLocalBrowsers();
  config.capabilities = browsers.map(browser => ({ browserName: browser.getId() }));

하지만 물론 단순하게 config.capabilities = ['firefox']로 구성해도 잘 작동합니다.

WebdriverIO를 종속성으로 설치한 경우(npm install --save-dev webdriverio), 다음과 같이

package.jsonscripts 속성에 wdio를 구성 파일 경로와 함께 실행하는 줄을 추가할 수 있습니다:

  "confidence-check": "wdio wdio.conf.js",

그런 다음 npm run confidence-check를 사용하여 테스트를 실행하면,

지정한 대로 애플리케이션과 상호작용하는 새로운 브라우저 창을 실제로 볼 수 있습니다.

GitLab CI/CD 구성

이제 우리의 흥미로운 부분으로 넘어갑니다: GitLab CI/CD에서 이를 실행하려면 어떻게 해야 할까요?

이를 위해 해야 할 두 가지가 있습니다:

  1. 실제로 브라우저가 사용 가능한 CI/CD 작업을 설정합니다.

  2. 검토 앱을 방문하기 위해 해당 브라우저를 사용하는 WebdriverIO 구성을 업데이트합니다.

이 기사 범위 내에서, 우리는 검토 앱을 배포하는 단계 후에 실행되는 추가 CI/CD 단계 confidence-check를 정의했습니다.

이는 node:latest Docker 이미지를 사용합니다. 그러나 WebdriverIO는 애플리케이션과 상호작용하기 위해 실제 브라우저를 시작하므로 이를 설치하고 실행해야 합니다.

게다가, WebdriverIO는 서로 다른 브라우저를 제어하기 위한 공통 인터페이스로 Selenium을 사용하므로, Selenium 또한 설치하고 실행해야 합니다.

운 좋게도, Selenium 프로젝트는 Firefox용 standalone-firefox

Chrome용 standalone-chrome의 Docker 이미지를 제공합니다.

(사파리 및 인터넷 익스플로러/엣지는 오픈 소스가 아니며 Linux에서 사용할 수 없으므로, 불행히도 GitLab CI/CD에서 사용할 수 없습니다).

GitLab CI/CD는 우리의 confidence-check 작업에 이러한 이미지를 연결하는 것을 쉽게 만들어줍니다.

services 속성을 사용하여 Selenium 서버를 이미지 이름 기반 호스트네임에서 사용할 수 있도록 합니다.

밑줄이 있는 호스트네임은 RFC에 유효하지 않아 제3자 애플리케이션에서 문제를 일으킬 수 있습니다. 자세한 내용은 서비스에 액세스하기를 참조하십시오.

예를 들어, Firefox 용 작업 구성은 다음과 같습니다:

e2e:firefox:
  stage: confidence-check
  services:
    - selenium/standalone-firefox
  script:
    - npm run confidence-check --host=selenium__standalone-firefox

Chrome도 마찬가지입니다:

e2e:chrome:
  stage: confidence-check
  services:
    - selenium/standalone-chrome
  script:
    - npm run confidence-check --host=selenium__standalone-chrome

이제 우리는 엔드 투 엔드 테스트를 실행할 작업을 갖게 되었으므로,

WebdriverIO에게 바로 옆에서 실행되는 Selenium 서버에 연결하는 방법을 알려야 합니다. 위에서 조금 속였던 것은,

명령줄에서 npm run confidence-checkhost 옵션의 값을 인수로 전달했기 때문입니다.

그러나 여전히 WebdriverIO에게 어떤 브라우저가 사용 가능한지 알려주어야 합니다.

GitLab CI/CD는 여러 가지 변수를 제공합니다

현재 CI 작업에 대한 정보입니다. 우리는 현재 실행 중인 작업에 따라 WebdriverIO 구성을 동적으로 설정하기 위해 이 정보를 사용할 수 있습니다.

보다 구체적으로, 우리는 현재 실행 중인 작업의 이름에 따라 WebdriverIO에게 어떤 브라우저에서 테스트를 실행할지를 알려줄 수 있습니다.

이는 위에서 이름을 wdio.conf.js로 명명한 WebdriverIO의 구성 파일에서 처리할 수 있습니다:

if(process.env.CI_JOB_NAME) {
    dynamicConfig.capabilities = [
        { browserName: process.env.CI_JOB_NAME === 'e2e:chrome' ? 'chrome' : 'firefox' },
    ];
}

마찬가지로 WebdriverIO에게 검토 앱이 실행되는 위치를 알려줄 수 있습니다 - 이 예제의 경우에는

<branch name>.flockademic.com에 있습니다:

if(process.env.CI_COMMIT_REF_SLUG) {
    dynamicConfig.baseUrl = `https://${process.env.CI_COMMIT_REF_SLUG}.flockademic.com`;
}

그리고 로컬 전용 구성은 _CI에서 실행되지 않을 때_만 사용되도록 보장할 수 있습니다 if (!process.env.CI).

그것이 기본적으로 GitLab CI/CD에서 엔드 투 엔드 테스트를 실행하는 데 필요한 모든 재료입니다!

요약하자면, 우리의 .gitlab-ci.yml 구성 파일은 다음과 같습니다:

default:
  image: node:8.10

stages:
  - deploy
  - confidence-check

deploy_terraform:
  stage: deploy
  script:
    # 귀하의 리뷰 앱 배포 스크립트 - 작업 예시를 보려면 https://gitlab.com/Flockademic/Flockademic/blob/5a45f1c2412e93810fab50e2dab8949e2d0633c7/.gitlab-ci.yml#L315를 확인하세요
    - echo
  environment: production

e2e:firefox:
  stage: confidence-check
  services:
    - selenium/standalone-firefox
  script:
    - npm run confidence-check --host=selenium__standalone-firefox

e2e:chrome:
  stage: confidence-check
  services:
    - selenium/standalone-chrome
  script:
    - npm run confidence-check --host=selenium__standalone-chrome

다음 단계

스스로 설정하고 프로덕션 프로젝트의 작업 구성을 살펴보려면 다음을 참고하세요:

WebdriverIO가 할 수 있는 것이 많이 있습니다. 예를 들어, 테스트가 실패할 때 WebdriverIO에 스크린샷을 찍도록 지시하기 위해 screenshotPath를 설정할 수 있습니다.

그런 다음 GitLab CI/CD에 이 artifacts를 저장하도록 지시하면, GitLab 내에서 무엇이 잘못되었는지 확인할 수 있습니다.