Подсушить тесты

от автора

TL;DR

Введение

Итак, руби-рельсы, браузерное тестирование, селениум, капибара и призма.

Про селениум и капибару не буду говорить, думаю, кто занимается тестированием, про это всё знают и без меня, а вот про призму хочу сказать пару слов.

SitePrism — это DSL (Domain Specific Language), который дает описание веб-страницы, удобное для проведения тестирования. SitePrism позволяет тестировщику структурно описать страницу, выделив части, подлежащие тестированию, и опустив несущественное.

Пример. Корзина магазина:

Описание для корзины, изображенной выше:

class Cart < SitePrism::Page   set_url '/cart.html'    element :header, 'h1'                                # Заголовок: "Shopping cart"                                                      sections :cart_items, 'div.cart_items' do            # Массив из товаров (sections - во множественном числе)     element :name, 'div.item-name'                     # Имя одного товара     element :image, 'img.item-image'                   # Картинка товара     element :price, 'div.item-price'                   # Цена за единицу     element :quantity, 'div.item-quantity'             # Кол-во     element :total, 'div.item-total'                   # Стоимость выбранных товаров   end    section :checkout, 'div.checkout' do                 # Раздел внизу с кнопкой  (section - в единственном числе)     element :total, 'div.checkout-total'               # Общая соимость заказа     element :checkout_button, 'button.checkout-button' # Кнопка   end end

Даже человек без подготовки, поглядев на картинку и описание, легко поймёт, что чему соответствует.

Имея подобное описание, можно написать тест вроде такого:

describe 'Cart' do   it 'is correct' do     page = Cart.new     page.load      # Проверили заголовок     expect(page.header.text).to eq('Shopping Cart')      # Убедились, что товара 2     expect(page.cart_items.size).to eq(2)      # Проверили первый товар     expect(page.cart_items[0].name.text).to match('Cup')     expect(page.cart_items[0].quantity.value).to match('1')     expect(page.cart_items[0].image[:src]).to match('cup.png')     expect(page.cart_items[0].price.text).to match('19.00')     expect(page.cart_items[0].total.text).to match('19.00')      # Проверили второй товар     expect(page.cart_items[1].name.text).to match('Cap')     expect(page.cart_items[1].quantity.value).to match('2')     expect(page.cart_items[1].image[:src]).to match('cap.png')     expect(page.cart_items[1].price.text).to match('24.00')     expect(page.cart_items[1].total.text).to match('48.00')      # Проверили подвал корзины     expect(page.checkout.total.text).to match('67.99')     expect(page.checkout.checkout_button.text).to match('Checkout')   end end

Скорее всего, это типичная картина проверки страницы в тесте. Очевидно, тест содержит избыточные, дублирующиеся слова, замедляющие как написание, так и чтение. Да, можно сократить, введя переменные, примерно так:

item = page.cart_items[0] expect(item.name.text).to match('Cup') expect(item.quantity.value).to match('1') expect(item.image[:src]).to match('cup.png') expect(item.price.text).to match('19.00') expect(item.total.text).to match('19.00')

Но всё равно жирно и многословно.

gem prism_checker

Я решил, что можно же просто взять призму и сказать, чего мы от нее ждём, а ждём мы соответствие такой вот структуре:

{   header: 'Shopping Cart',   cart_items: [     {       name: 'Cup',       image: 'cup.png',       price: '19.00',     },     {       name: 'Cap',       image: 'cap.png',       price: '24.00',     }   ],   checkout: {     total: '67.00',     checkout_button: 'Checkout'   } }

Вся необходимая информация есть, минимальное количество слов, в тесте такая приятная легкость образовалась. Никакого жира, один рельеф, осушили по-максимуму.

Эту идею я реализовал в gem-е PrismChecker, который позволяет коротко описывать, что мы ожидаем от призмы. Вот так:

# RSpec-версия expect(page).to be_like(   header: 'Shopping Cart',   cart_items: [     {       name: 'Cup',       image: 'cup.png',       price: '19.00',     },     {       name: 'Cap',       image: 'cap.png',       price: '24.00',     }   ],   checkout: {     total: '67.00',     checkout_button: 'Checkout'   } )
# MiniTest-версия assert_page_like(page,   header: 'Shopping Cart',   cart_items: [     # ...   ],   checkout: {     # ...   } )

Иными словами, PrismChecker проверяет призму на соответствие некоторому хэшу.

Грубо говоря, element-у ставится в соответствие строка, section-у — хэш, а elements и sections проверяются с помощью массива.

# element assert_page_like(page, header: 'Shopping Cart') assert_page_like(page.header, 'Shopping Cart')  # section assert_page_like(page, checkout: {   total: '67.00',   checkout_button: 'Checkout' }) assert_page_like(page.checkout,    total: '67.00',   checkout_button: 'Checkout' )  # elements, sections assert_page_like(page, cart_items: [   {     name: 'Cup',     price: '19.00',   },   {     name: 'Cap',     price: '24.00',   } ])

В случае ошибок будет выдано сообщение такого вида:

Цветные буквы пока завезли только в RSpec, MiniTest - чёрно-белый.

Цветные буквы пока завезли только в RSpec, MiniTest — чёрно-белый.

Подробности

Установка

для RSpec:

# Gemfile  gem 'prism_checker_rspec'
# spec_helper.rb require 'prism_checker_rspec'

для MiniTest:

# Gemfile gem 'prism_checker_minitest'
# test_helper.rb require 'prism_checker_minitest'

Примеры

Проверка секции и двух дочерних элементов:

assert_page_like(page, checkout: {   total: '67.00',   checkout_button: 'Checkout' })

Если первый аргумент является классом SitePrism::Page, то при тестировании вначале будет выполнена проверка, что страница загружена. Элементы и секции сначала проверяются на видимость, потом на соответствие:

assert_page_like(page, button: 'Button') # assert(page.loaded?) # assert(page.button.visible?) # assert_match(page.button.text, 'Button')

Если элемент является изображением, то проверяемая строка будет сравниваться с атрибутом src. Для input и textarea проверяется value. Checkbox или radio можно проверить следующим образом:

assert_page_like(page, checkbox: true) assert_page_like(page, checkbox: {checked: true})

element можно сравнивать не только со строкой, но и с хэшем:

assert_page_like(page.image,                  src: 'logo.png',                  class: 'logo',                  alt: 'Logo')

Проверить, что элемент/секция видимы/невидимы или отсутствуют:

assert_page_like(page,                   header: :visible,                   checkout: :invisible )  assert_page_like(page, checkout: :absent)

Элементы и секции вначале проверяются на то, что содержат правильное количество записей:

assert_page_like(page,                  items: [                    'Item 1',                    'Item 2'                  ]) # assert(page.loaded?) # assert_equal(page.items.size, ["Item 1", "Item 2"].size) # ...

Элементы и секции можно проверять просто на размер:

assert_page_like(page, items: 2) # assert(page.loaded?) # assert_equal(page.items.size, 2)

Со строкой можно сравнивать не только element, но и page, section, sections, elements:

assert_page_like(page, 'Shopping Cart') # assert(page.loaded?) # assert_match(page.text, 'Shopping Cart')

Вместо строки можно использовать регулярные выражения:

assert_page_like(page, /Shopping Cart/)

Если нужно проверить, что текст элемента есть пустая строка, то может возникнуть проблема. По умолчанию проверяется вхождение подстроки, а пустая строка входит в любую строку:

assert_page_like(page, header: '')  # Всегда сработает, даже если header не пуст

Эту проблему можно решить с regexp или специальной проверкой:

assert_page_like(page, header: /^$/)  assert_page_like(page, header: :empty)

По умолчанию строки сравниваются путем поиска подстроки, но можно настроить гем на точное соответствие:

assert_page_like(page, header: 'Cart') # будет проверено вот так: header.include?('Cart')  PrismChecker.string_comparison = :exact # Точное соответствие assert_page_like(page, header: 'Cart') # будет проверено вот так: header == 'Cart'

Еще примеры можно найти на странице проекта, на гитхабе.

Итого

Gem PrismChecker упрощает написание и чтение браузерных тестов и бережет нервы тестировщиков.

Буду рад услышать отзывы, кртику, баги.


ссылка на оригинал статьи https://habr.com/ru/articles/793308/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *