Galen 프레임워크를 사용한 레이아웃 테스트 기술
게시 됨: 2022-03-10그래픽 사용자 인터페이스를 디자인할 때 항상 열려 있는 질문이 있습니다. 테스트를 자동화하려면 어떻게 해야 합니까? 그리고 웹사이트 레이아웃이 반응을 유지하고 다양한 해상도를 가진 모든 종류의 장치에서 올바르게 표시되도록 하려면 어떻게 해야 합니까? 여기에 동적 콘텐츠, 국제화 및 현지화 요구 사항으로 인해 발생하는 복잡성이 추가되면 실제 문제가 됩니다.
이 기사에서는 흥미로운 새로운 레이아웃 테스트 기술을 안내합니다. Galen Framework를 사용하여 의미 있는 일반화된 레이아웃 테스트를 작성하기 위한 자세한 자습서를 제공할 것입니다. 이 테스트는 모든 브라우저와 모든 장치에서 실행할 수 있고 동시에 디자인 문서에서 단일 소스로 사용할 수 있습니다.
SmashingMag에 대한 추가 정보:
- 반응형 인터페이스 디자인을 위한 시각적 테스트 주도 개발
- 앱, 게임 및 모바일 웹용 테스트 자동화의 기초
- React Native 앱을 위한 다양한 테스트 자동화 프레임워크
또한 광고 웹사이트인 Marktplaats에서 메시징 페이지에 대한 최적화된 테스트를 생각해 낸 방법을 보여드릴 것입니다. Galen의 구문을 우리 언어로 확장하는 방법, 테스트 코드를 개선하는 방법 및 레이아웃 테스트 루틴을 예술로 바꾸는 방법을 배웁니다.
갈렌 프레임워크 소개
Galen Framework는 1년 전 "반응형 인터페이스 디자인을 위한 시각적 테스트 주도 개발"에서 다루었습니다. 당시에는 구문이 제한적이었습니다. 그 이후로 많이 개선되었고 많은 새로운 기능을 얻었습니다. 여기에서 살펴보겠습니다.
Galen Framework에 익숙하지 않은 경우 Galen Specs라는 자체 테스트 언어를 사용하여 응답 및 브라우저 간 레이아웃 테스트 및 기능 테스트를 위한 도구입니다. Selenium WebDriver를 기반으로 하며 WebDriver로 직접 작업할 수 있는 풍부한 JavaScript API도 있습니다. WebDriver를 제어할 수 있기 때문에 모든 브라우저, 클라우드(SauceLabs, BrowserStack, PerfectoMobile 등) 또는 Appium을 사용하는 실제 모바일 장치에서 테스트를 실행할 수 있습니다.
설치 및 실행
Galen Framework를 설정하는 것은 쉽습니다. npm을 통해 설치하려면 다음 명령을 실행하기만 하면 됩니다.
npm install -g galenframework-cli
npm을 사용하지 않는 경우 최신 Galen Framework 아카이브를 다운로드하고 패키지를 추출한 다음 설치 지침을 따르십시오.
Galen Framework는 한 번 설치하면 다양한 방법으로 실행할 수 있습니다. 예를 들어, check
명령을 사용하여 단일 페이지에 대한 빠른 테스트를 시작할 수 있습니다. 이 명령의 경우 레이아웃 유효성 검사와 함께 .gspec
파일을 제공해야 하며 다음과 같이 호출할 수 있습니다.
galen check loginPage.gspec --url https://example.com --size 1024x768 --include desktop --htmlreport reports
이 명령은 브라우저를 시작하고 지정된 URL을 열고 브라우저 창의 크기를 1024 × 768 픽셀로 조정하고 loginPage.gspec
파일에 선언된 모든 유효성 검사를 실행합니다. 결과적으로 자세한 HTML 보고서를 얻을 수 있습니다.
테스트 스위트 관리
현실 세계에서 실제 웹 애플리케이션은 순전히 정적 페이지로 구성되지 않습니다. 확인하려는 위치에 도달하기 위해 몇 가지 작업을 수행해야 하는 경우가 많습니다. 이 경우 Galen은 페이지 개체 모델을 구현하기 위한 JavaScript 테스트 제품군과 GalenPages JavaScript API를 제공합니다. 다음은 JavaScript Galen 테스트의 간단한 예입니다.
test("Home page", function() { var driver = createDriver("https://galenframework.com", "1024x768"); checkLayout(driver, "homePage.gspec", ["desktop"]); });
그리고 다음은 실제 프로젝트에서 가져온 로그인 페이지에 대한 페이지 개체 모델의 구현입니다.
WelcomePage = $page("Welcome page", { loginButton: "#welcome-page .button-login" }); LoginPage = $page("Login page", { username: "input[name='login.username']", password: "input[name='login.password']", loginButton: "button.button-login" loginAs: loggedFunction ("Log in as ${_1.username} with password ${_1.password}", function(user) { this.username.typeText(user.username); this.password.typeText(user.password); this.loginButton.click(); }) }); test("Login page", function() { var driver = createDriver("https://testapp.galenframework.com", "1024x768"); var welcomePage = new WelcomePage(driver).waitForIt(); welcomePage.loginButton.click(); new LoginPage(driver).waitForIt(); checkLayout(driver, "loginPage.gspec", ["desktop"]); });
고급 사용을 위해서는 Galen Bootstrap 프로젝트를 살펴보는 것이 좋습니다. Galen을 위해 특별히 제작된 JavaScript 확장 프로그램입니다. UI 테스트를 위한 몇 가지 추가 기능과 브라우저를 구성하고 복잡한 테스트 제품군을 실행하는 더 쉬운 방법을 제공합니다.
간단한 레이아웃 테스트
Galen Framework에서 간단한 레이아웃 테스트를 소개하는 것으로 시작하겠습니다. 그런 다음 고급 사용 사례로 이동하여 Galen Specs 구문을 확장하는 방법을 보여줍니다. 이를 위해 아이콘과 캡션이 있는 헤더를 살펴보겠습니다.

HTML 코드에서는 다음과 같이 보일 수 있습니다.
<body> <!-- … --> <div> <img class="header-logo" src="/imgs/header-logo.png"/> <h1>My Blog</h1> </div> <!-- … --> </body>
Galen 레이아웃 테스트의 가장 간단한 형태는 다음과 같습니다. 먼저 CSS 선택기로 객체를 선언해야 합니다.
@objects header #header icon #header img caption #header h1
그런 다음 의미 있는 이름으로 테스트 섹션을 선언하고 그 아래에 모든 유효성 검사를 넣습니다.
= Icon and Caption = icon: left-of caption 10 to 15px width 32px height 32px inside header 10px top caption: aligned horizontally all header inside header
여기에서는 아이콘과 캡션의 두 가지 헤더 요소를 테스트했습니다. 아이콘 및 캡션 요소 아래에 나열된 모든 유효성 검사는 실제로 표준 Galen 사양입니다. 이러한 사양은 고유한 레이아웃 테스트 솔루션을 조합할 수 있는 기본 빌딩 블록입니다. 각 사양은 단일 속성(예: 너비, 높이, 텍스트), 상대적 위치(예: 내부, 왼쪽, 위) 또는 스크린샷의 픽셀(예: 색 구성표, 이미지)을 확인합니다.
forEach 루프를 사용하여 여러 요소 테스트
이전 예제는 간단한 시나리오를 보여줍니다. 수평 메뉴라는 더 복잡한 상황을 처리하는 방법을 살펴보겠습니다. 먼저 간단한 레이아웃 테스트 기술을 시도해 보겠습니다.

페이지에서 여러 요소를 일치시키는 것으로 시작합니다. 다음 코드를 사용하여 Galen에게 #menu ul li
CSS 선택기와 일치하는 요소를 검색하도록 지시합니다.
@objects menu #menu item-* ul li
나중에 menu.item-1
및 menu.item-2
와 같은 이름으로 이러한 항목을 참조하고 @forEach
루프를 사용하여 모든 메뉴 항목을 반복할 수 있습니다.
= Menu = menu.item-1: inside menu 0px top left bottom @forEach [menu.item-*] as menuItem, next as nextItem ${menuItem}: left-of ${nextItem} 0px aligned horizontally all ${nextItem}
보시다시피 실제 검사는 그렇게 복잡하지 않지만 코드는 이미 덜 직관적입니다. 테스트에 더 유사한 코드가 있다고 상상해보십시오. 어느 순간에는 관리할 수 없는 엉망이 될 것입니다. 개선할 수 있는 방법이 있어야 합니다.
레이아웃 테스팅 재고하기
앞의 예를 생각해보면 레이아웃을 한두 문장으로 표현할 수 있을 것 같습니다. 예를 들어, “모든 메뉴 항목은 사이에 여백 없이 수평으로 정렬되어야 합니다. 첫 번째 메뉴 항목은 여백 없이 메뉴 왼쪽에 위치해야 합니다.” 우리가 원하는 레이아웃을 설명하기 위해 문장을 공식화했기 때문에 우리 코드에서 그냥 사용할 수 없는 이유는 무엇입니까? 다음과 같은 코드를 작성할 수 있다고 상상해보십시오.
= Menu = |first menu.item-* is in top left corner of menu |menu.item-* are aligned horizontally next to each other
사실, 그것은 내 프로젝트에서 복사한 실제 작업 코드입니다. 마지막 두 줄(파이프 |
로 시작)에서 우리는 두 문장을 구문 분석하여 인수를 수집하는 사용자 정의 함수를 호출하고 있습니다. 물론 위의 예는 그대로 작동하지 않습니다. 컴파일을 하려면 이 두 명령문에 대한 핸들러를 구현해야 합니다. 나중에 이 구현으로 다시 돌아올 것입니다.
위의 예에서 요점은 레이아웃 테스트가 객체 주도에서 표현식 기반 테스트로 바뀌 었다는 것입니다. 이러한 사소한 예에서는 명확하지 않을 수 있지만 더 큰 규모에서는 확실히 눈에 띕니다. 왜 이것이 중요한가요? 짧은 대답은 이것이 우리의 사고방식을 바꾸고 소프트웨어를 설계하고 테스트를 작성하는 방식에 영향을 미친다는 것입니다.
이 기술을 사용하면 페이지를 특정 관계가 있는 개체 묶음으로 취급하지 않습니다. 개별 요소의 CSS 속성은 테스트하지 않습니다. 그리고 우리는 복잡하고 중요하지 않은 코드를 작성하지 않습니다. 대신 일반적인 레이아웃 패턴과 의미 있는 문장을 생각하려고 합니다. 메뉴 항목 1, 메뉴 항목 2 등을 별도로 테스트하는 대신 다음과 같은 일반 명령문을 적용합니다.
- 다른 요소에서 재현 가능합니다.
- 하드코딩된 픽셀 값을 포함하지 마십시오.
- 추상화에 적용되고 구체적인 객체에는 적용되지 않습니다.
- 그리고 마지막으로 중요한 것은 우리가 그것들을 읽을 때 실제로 의미가 있다는 것입니다.
작동 원리
이 간단한 예를 사용하여 사용자 정의 레이아웃 표현식의 메커니즘을 설명하겠습니다.

이 예에서는 버튼이 왼쪽이나 오른쪽에 여백 없이 패널까지 늘어나는지 확인해야 합니다. 사용자 지정 규칙이 없으면 다른 방식으로 접근할 수 있지만 다음 솔루션을 선호합니다.
button: inside some_panel 0px left right
위의 코드는 측면에 사용자 지정 여백을 선언할 수 있는 유연성을 제공하며 버튼이 패널 내에 완전히 포함되어 있는지 암시적으로 테스트합니다. 단점은 가독성이 좋지 않다는 것입니다. 그래서 이 유효성 검사를 표현식 button stretches to some_panel
뒤에 추가하려고 합니다. 이것이 작동하려면 다음과 같은 사용자 지정 규칙을 작성해야 합니다.
@rule %{elementName} stretches to %{parentName} ${elementName}: inside ${parentName} 0px left right
그게 다야 이제 한 줄로 테스트에 넣을 수 있습니다.
| button stretches to some_panel
보시다시피 이 규칙은 elementName
과 parentName
이라는 두 개의 인수를 사용합니다. 이를 통해 다른 요소에도 적용할 수 있습니다. 이 두 개체의 이름을 바꾸면 됩니다.
| login_panel stretches to main_container | header stretches to screen | footer stretches to screen # etc.
자체 테스트 언어 구현
가로 메뉴에 대한 레이아웃 표현의 초기 예를 살펴보겠습니다.
= Menu = | first menu.item-* is in top left corner of menu | menu.item-* are aligned horizontally next to each other
다음과 같은 방법으로 첫 번째 규칙을 구현할 수 있습니다.
@rule first %{itemPattern} is in %{cornerSides} corner of %{parentElement} @if ${count(itemPattern) > 0} ${first(itemPattern).name}: inside ${parentElement} 0px ${cornerSides}
이 예에서 사용하면 다음과 같이 인수를 구문 분석합니다.
-
itemPattern
=menu.item-*
-
cornerSides
=top left
-
parentElement
=menu
첫 번째 표현이 끝났기 때문에 다음 표현으로 넘어갈 수 있습니다. 두 번째 표현식에서는 모든 메뉴 항목의 수평 정렬을 테스트해야 합니다. 저는 세 가지 간단한 단계를 제안합니다.
- 모든 메뉴 항목을 찾습니다.
- 끝에서 두 번째 요소까지 모든 항목을 반복합니다.
- 요소
n
이 요소n+1
의 왼쪽에 있고 위쪽 및 아래쪽 가장자리가 정렬되어 있는지 확인합니다.
작동하게 하려면 @forEach
루프와 left-of
및 aligned
사양을 가져와야 합니다. 다행히 Galen에서는 루프에서 이전 또는 다음 항목을 참조할 수 있습니다. 다음 요소에 대한 참조를 선언한 경우, 정확히 우리가 필요로 하는 마지막 두 번째 요소까지만 반복됩니다.
@rule %{itemPattern} are aligned horizontally next to each other @forEach [${itemPattern}] as item, next as nextItem ${item}: left-of ${nextItem} 0px aligned horizontally all ${nextItem}
테스트에서 여백을 지정해야 하는 경우(예: ~ 20px
또는 10 to 20px
) 어떻게 될까요? 그런 다음 별도의 규칙을 구현하거나 %{margin}
인수를 지원하도록 기존 규칙을 확장하는 것이 좋습니다.
@rule %{itemPattern} are aligned horizontally next to each other with %{margin} margin @forEach [${itemPattern}] as item, next as nextItem ${item}: left-of ${nextItem} ${margin} aligned horizontally all ${nextItem}
그게 다야! 가로 메뉴의 유효성을 검사하는 데 도움이 되는 일반 표현식을 만들었습니다. 그러나 유연성 덕분에 우리는 그보다 훨씬 더 많은 일을 할 수 있습니다. 이를 사용하여 페이지의 다른 요소를 테스트할 수 있습니다. 두 버튼의 정렬을 테스트하는 데 사용할 수도 있습니다.

| menu.item-* are aligned horizontally next to each other with 0px margin | submit_button, cancel_button are aligned horizontally next to each other with 20px margin
이 두 가지 예에서 첫 번째 인수를 두 가지 다른 방식으로 선언했음을 알 수 있습니다. 첫 번째 표현식에서 첫 번째 인수는 “menu.item-*”
이고 두 번째 표현식에서 “submit_button, cancel_button”
으로 선언됩니다. @forEach
루프를 사용하면 별 연산자와 함께 쉼표로 구분된 개체 목록을 사용할 수 있기 때문에 가능합니다. 하지만 아직 리팩토링이 끝나지 않았습니다. 코드를 더 개선하고 더 읽기 쉽게 만들 수 있습니다. 메뉴 항목과 로그인 양식 버튼에 대한 그룹을 생성하면 다음과 같은 작업을 수행할 수 있습니다.
@groups menu_items menu_item-* login_form_buttons submit_button, cancel_button = Testing login page = | &menu_items are aligned horizontally next to each other with 0px margin | &login_form_buttons are aligned horizontally next to each other with 20px margin
이 경우 그룹 선언을 나타내는 &
기호를 사용해야 합니다. 그것은 이미 좋은 시험입니다. 첫째, 제대로 작동하고 우리가 필요한 것을 테스트할 수 있습니다. 또한 코드가 명확하고 읽기 쉽습니다. 다른 사람이 로그인 페이지가 어떻게 생겼는지, 디자인 요구 사항이 무엇인지 묻는다면 테스트를 보라고 말할 수 있습니다.

보시다시피 복잡한 레이아웃 패턴에 대한 사용자 정의 표현식을 구현하는 것은 실제로 큰 문제가 아닙니다. 처음에는 어려울 수 있지만 여전히 창의적인 활동과 유사합니다.
동적 여백
다양한 웹사이트에서 가끔 볼 수 있는 또 다른 보기 드문 레이아웃 패턴을 살펴보겠습니다. 요소 간의 거리가 동일한지 테스트하려면 어떻게 해야 합니까? 이를 위해 다른 규칙을 구현해 보겠습니다. 하지만 이번에는 JavaScript 구현을 사용합니다. 나는 “box_item-* are aligned horizontally next to each other with equal distance”
진술을 제안합니다. 이것은 요소 사이의 여백을 모르고 픽셀 값을 하드코딩할 수 없기 때문에 약간 까다로울 것입니다. 따라서 가장 먼저 해야 할 일은 첫 번째 요소와 마지막 요소 사이의 실제 여백을 검색하는 것입니다.

그 여백을 얻으면 이전과 유사하게 @forEach
루프에서 이를 선언할 수 있습니다. 필요한 로직이 이전의 모든 예제보다 조금 더 복잡하기 때문에 JavaScript API를 사용하여 이 규칙을 구현하는 것을 제안합니다. my-rules.js
라는 파일을 만들고 다음 코드를 입력해 보겠습니다.
rule("%{objectPattern} are aligned horizontally next to each other with equal margin", function (objectName, parameters) { var allItems = findAll(parameters.objectPattern), distance = Math.round(Math.abs(allItems[1].left() - allItems[0].right())), expectedMargin = (distance - 1) + " to " + (distance + 1) + "px"; if (allItems.length > 0) { for (var i = 0; i < allItems.length - 1; i += 1) { var nextElementName = allItems[i + 1].name; this.addObjectSpecs(allItems[i].name, [ "aligned horizontally all " + nextElementName, "left-of " + nextElementName + " " + expectedMargin ]); } } });
테스트 코드에서는 다음과 같이 사용합니다.
@script my-rules.js # … = Boxes = | box_item-* are aligned horizontally next to each other with equal distance
보시다시피 Galen Framework에서는 규칙을 구현할 때 Galen 사양과 JavaScript라는 두 가지 언어 중에서 선택할 수 있습니다. 간단한 표현식의 경우 Galen Specs가 사용하기 더 쉽지만 복잡한 표현식의 경우 항상 JavaScript를 선택합니다. JavaScript 규칙에 대해 자세히 알아보려면 설명서를 참조하세요.
갈렌 엑스트라
다양한 레이아웃 패턴을 충분히 사용해 본 결과, 이 모든 Galen 규칙이 다른 테스트 프로젝트에 쉽게 적용될 수 있다는 것을 깨달았습니다. 가장 일반적인 레이아웃 표현식을 자체 라이브러리로 컴파일하는 아이디어를 얻었습니다. 그것이 내가 Galen Extras 프로젝트를 만들게 된 방법입니다. 다음은 이 라이브러리의 기능에 대한 몇 가지 예입니다.
| header.icon should be squared | amount of &menu_items should be > 3 | &menu_items are aligned horizontally next to each other | &list_items are aligned vertically above each other with equal distance | every &menu_item is inside menu 0px top and has width > 50px | first &menu_item is inside menu 0px top left | &menu_items are rendered in 2 column table | &menu_items are rendered in 2 column table, with 0 to 1px vertical and 10px horizontal margin | &login_form_elements sides are vertically inside content_container with 20px margin login_panel: | located on the left side of panel and takes 70 % of its width # etc …
Galen Extras 라이브러리에는 웹사이트에서 흔히 볼 수 있는 많은 레이아웃 패턴이 포함되어 있으며 유용한 패턴을 발견하는 즉시 계속 업데이트합니다. 이 라이브러리가 설정되면 실제 테스트 프로젝트에서 사용하기로 결정했습니다.
메시징 앱 테스트
현재 Marktplaats에서 소프트웨어 엔지니어로 일하고 있습니다. 어느 시점에서 나는 내가 얻은 모든 경험을 실제 프로젝트에 적용하기로 결정했습니다. 웹사이트에서 메시징 페이지를 테스트해야 했습니다. 다음과 같이 보입니다.

솔직히 말해서, 그러한 페이지에 대한 테스트를 구현하는 것은 항상 나에게 약간 무섭게 느껴졌습니다. 특히 레이아웃 테스트가 그렇습니다. 그러나 Galen Extras 라이브러리가 있으면 실제로 매우 원활하게 진행되었으며 곧 다음 코드를 만들 수 있었습니다.
@import ../selected-conversation.gspec @groups (message, messages) messenger.message-* first_two_messages messenger.message-1,messenger.message-2 first_message messenger.message-1 second_message messenger.message-2 third_message messenger.message-3 (message_date_label, message_date_labels) messenger.date_label-* first_date_label messenger.date_label-1 second_date_label messenger.date_label-2 = Messages panel = = Messages and Date labels = |amount of visible &message_date_labels should be 1 |first &message_date_label has text is "17 november 2015" |amount of visible &messages should be 3 |&first_two_messages should be located at the left inside messenger with ~ 20px margin |&third_message should be located at the right inside messenger with ~ 20px margin |&messages are placed above each other with 10 to 15px margin |text of all &messages should be ["Hi there!", "I want to buy something", "Hello! Sure, it's gonna be 100 euros"] = Styling = |&first_two_messages should be styled as others message |&third_message should be styled as own message
픽셀 범위 추출
테스트는 괜찮아 보였습니다. 작고 읽기 쉽지만 여전히 완벽하지는 않습니다. 나는 그 모든 여백 정의( ~ 20px
, 10 to 15px
)가 마음에 들지 않았습니다. 그 중 일부가 반복되어 각각이 무엇을 의미하는지 이해하기 어려웠습니다. 그래서 의미 있는 변수 뒤에 모든 여백을 숨기기로 결정했습니다.
# ... @set messages_side_margin ~ 20px messages_vertical_margin 10 to 15px = Messages panel = = Messages and Date labels = |amount of visible &message_date_labels should be 1 |first &message_date_label has text is "17 november 2015" |amount of visible &messages should be 3 |&first_two_messages should be located at the left inside messenger with ${messages_side_margin} margin |&third_message should be located at the right inside messenger with ${messages_side_margin} margin |&messages are placed above each other with ${messages_vertical_margin} margin # ...
보시다시피 여백을 messages_vertical_margin
및 messages_side_margin
으로 옮겼습니다. 또한 0에서 1픽셀 사이의 범위인 minimal
여백을 선언했습니다.
# ... @set minimal 0 to 1px = Conversations Panel = | &conversations are aligned above each other with ${minimal} margin # ...
이미지 기반 유효성 검사 및 사용자 지정 표현식
페이지의 모든 주요 요소의 위치를 다루고 스타일링도 테스트하기로 결정했습니다. 각 메시지에 사용자의 역할과 관련된 배경색이 있는지 확인하고 싶었습니다. 사용자가 로그인하면 메시지의 배경이 하늘색입니다. 다른 사용자에 대한 메시지는 흰색 배경을 갖습니다. 메시지가 전송되지 않은 경우 오류 경고는 분홍색 배경으로 표시됩니다. 다음은 이러한 스타일을 검증하는 데 도움이 된 규칙입니다.
@set OWN_MESSAGE_COLOR #E1E8F5 OTHERS_MESSAGE_COLOR white ERROR_MESSAGE_COLOR #FFE6E6 @rule %{item} should be styled as %{style} message ${item}: @if ${style === "own"} color-scheme > 60% ${OWN_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR} @elseif ${style === "error"} color-scheme > 60% ${ERROR_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR} @else color-scheme > 60% ${OTHERS_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR}
color-scheme
사양은 요소 내에서 색의 비례 분포를 확인합니다. 페이지의 스크린샷을 자르고 색상 분포를 분석합니다. 따라서 요소의 배경색을 확인하려면 해당 분포가 전체 색상 범위의 60% 이상인지 확인하면 됩니다. 테스트에서 이 규칙은 다음과 같이 호출됩니다.
= Styling = |&first_two_messages should be styled as others message |&third_message should be styled as own message
테스트 스위트 구성
메시징 앱은 RESTful 메시징 API와 함께 작동하는 동적 애플리케이션입니다. 따라서 모든 다른 상태에서 레이아웃을 테스트하려면 테스트 데이터를 준비해야 합니다. 테스트 스위트에서 모든 테스트 메시지를 구성할 수 있도록 Messaging API를 조롱하기로 결정했습니다. 다음은 테스트가 어떻게 구성되어 있는지 보여주는 테스트 모음의 일부입니다.
// ... testOnAllDevices("Unselected 2 conversations", "/", function (driver, device) { mock.onGetMyConversationsReturn(sampleConversations); refresh(driver); new MessageAppPage(driver).waitForIt(); checkLayout(driver, "specs/tests/unselected-conversations.gspec", device.tags); }); testOnAllDevices("When clicking a conversation it should reveal messages", "/", function (driver, device) { mock.onGetMyConversationsReturn(sampleConversations); mock.onGetSingleConversationReturn(sampleMessages); refresh(driver); var page = new MessageAppPage(driver).waitForIt(); page.clickFirstConversation(); checkLayout({ driver: driver, spec: "specs/tests/three-simple-messages-test.gspec", tags: device.tags, vars: { expectedTextProvider: textProvider({ "messenger.message-1": "Hi there!\n11:02", "messenger.message-2": "I want to buy something\n12:02", "messenger.message-3": "Hello! Sure, it's gonna be 100 euros\n13:02" }) } }); }); // ...
벌레 잡기
이러한 간단한 표현을 구현하면 꽤 빨리 효과를 볼 수 있습니다. 테스트 스위트에서 어떤 종류의 버그를 잡을 수 있는지 살펴보겠습니다.
스타일링 문제
다음은 CSS 코드 기반에서 문제가 발생하여 결과적으로 모든 메시지가 동일한 배경으로 렌더링되는 경우의 예입니다.

이 스크린샷을 원본과 비교하면 마지막 메시지의 배경이 흰색인 반면 밝은 파란색이어야 한다는 것을 알 수 있습니다. Galen이 이 문제를 보고하는 방법을 살펴보겠습니다.

강조 표시된 개체의 경우 color #e1e8f5 on “messenger.message-3” is 0% but it should be greater than 60%
. 솔직히 이 오류 메시지는 명확해 보이지 않지만 이 검사는 사용자 지정 규칙에서 생성되었기 때문에 항상 보고서 분기에서 원래 이름을 조회할 수 있습니다.

위로 스크롤하면 원래 명령문이 &third_message should be styled as own message
. 이것이 사용자 정의 표현식 사용의 또 다른 이점입니다. 사용자가 실패를 이해하고 생성된 모든 유효성 검사를 훌륭하게 설명하는 데 도움이 됩니다.
포지셔닝 문제
다음은 요소의 잘못된 정렬로 인해 레이아웃이 잘못된 경우의 또 다른 예입니다. 다음 스크린샷에서 마지막 메시지가 메시징 뷰포트의 오른쪽이 아닌 왼쪽에 위치하는 것을 볼 수 있습니다.

오류 메시지가 있는 스크린샷을 다시 살펴보겠습니다.

스크린샷은 메시징 컨테이너와 마지막 메시지 요소를 강조 표시합니다. 이와 함께 다음 오류 메시지가 표시됩니다. “messenger.message-3” is 285px right which is not in range of 22 to 28px
. 웹 개발자에게는 오른쪽에 22~28픽셀의 여백이 필요한 이유가 명확하지 않을 수 있습니다. 다시 말하지만 보고서 분기에서 유효성 검사 문을 찾아야 합니다.

해당 수표에 대한 원래 명령문은 &third_message should be located at the right inside messenger with ~ 25px margin
. 훨씬 더 의미가 있습니다. 또한 다른 프런트 엔드 엔지니어는 테스트를 작성하지 않은 경우에도 이 테스트 보고서를 이해할 수 있습니다.
레이아웃 테스트 지침
이러한 다양한 실험을 염두에 두고 모든 학습을 일반 레이아웃 테스트 지침으로 공식화하기로 결정했습니다. 다음은 테스트 루틴을 쉽게 수행하기 위해 따라야 할 단계의 빠른 체크리스트입니다.
- 디자인에서 레이아웃 패턴을 식별합니다.
- 유효성 검사 문을 일반화합니다. 대부분의 유효성 검사를 단일 문장으로 압축하십시오.
- 컴포넌트화! 반복되는 요소의 테스트를 전용 구성 요소로 옮기는 것이 항상 더 좋습니다.
- 섹션, 규칙 및 개체에 의미 있는 이름을 사용합니다.
- 픽셀을 피하십시오. 픽셀 값(정확한 값 또는 범위)을 의미 있는 변수로 바꾸십시오.
- 테스트하기 쉽도록 웹사이트의 코드를 조정하세요. 이렇게 하면 프로덕션 코드와 테스트 코드를 모두 구성하고 유지 관리하는 데 도움이 됩니다.
구조에 대한 수락 기준
종종 “레이아웃 테스트는 얼마나 상세해야 합니까?”와 같은 질문을 받습니다. 그리고 구체적으로 무엇을 테스트해야 합니까?” 일반적인 답변은 어렵습니다. 문제는 테스트의 적용 범위가 작을 때 버그를 놓친다는 것입니다. 반면에 너무 세부적인 테스트가 있으면 오탐을 많이 받을 수 있고, 앞으로 테스트 유지 관리에서 길을 잃을 수 있습니다. 따라서 절충안이 있습니다. 그러나 나는 나 자신을 위한 일반적인 지침을 알아냈습니다. 작업을 더 작은 사용자 스토리로 나누면 허용 기준의 형태로 페이지 디자인을 구성하는 것이 더 쉬워집니다. 결국, 바로 이 허용 기준을 테스트 코드에 넣을 수 있습니다. 예를 들어, 이러한 명령문 중 일부는 이전의 모든 코드 예제에서 볼 수 있는 것처럼 사용자 지정 규칙의 형태로 정의될 수 있습니다. 허용 기준의 좋은 예는 다음과 같습니다.
- 팝업은 화면의 세로 및 가로 중앙에 있어야 합니다.
- 너비는 400픽셀이어야 합니다.
- 버튼은 수평으로 정렬되어야 합니다.
- 등등
디자인을 간단한 문장으로 설명하면 재사용 가능한 문장으로 변환하고 테스트 코드를 구성하는 것이 더 쉬워집니다.
결론
보시다시피, 이러한 연습은 디자인을 구조화하고 여러 페이지 구성 요소에서 공유할 수 있는 일반적인 레이아웃 패턴을 발견하는 데 도움이 됩니다. 페이지가 복잡하고 많은 요소로 구성되어 있더라도 레이아웃 표현식에서 이를 그룹화하는 방법을 항상 찾을 수 있습니다. 이 접근 방식을 사용하면 레이아웃 테스트가 테스트 주도 개발을 위한 도구가 되어 소프트웨어를 점진적으로 설계, 구현 및 제공할 수 있게 되며, 이는 애자일 환경에서 특히 유용합니다.
자원
- 갈렌 프레임워크(공식 웹사이트)
- Galen 프레임워크, GitHub
- Galen Extras(라이브러리), GitHub
- Galen 부트스트랩, GitHub
- "Galen 프레임워크 자습서", YouTube