Playwright ve Cucumber ile BDD Test
Behavior Driven Development (BDD)
BDD,Davranış Odaklı Geliştirme yazılımın davranışlarını tanımlamaya odaklanan bir geliştirme yöntemidir. Bu yöntem, yazılımın nasıl çalışması gerektiğini belirlemek için iş analistleri, geliştiriciler ve kalite güvence ekipleri arasında işbirliğini teşvik eder. BDD’de genellikle Gherkin dili kullanılarak senaryolar yazılır. Senaryolar şu formatta yazılır:
- Given (Ön Koşul): Yazılımın başlangıç durumu.
- When (Olay): Kullanıcının gerçekleştirdiği eylem.
- Then (Sonuç): Beklenen sonuç veya sistemin tepkisi.
TDD ve BDD Arasındaki Farklar
- Odak Noktası: TDD, kodun test edilebilirliğine odaklanırken, BDD, yazılımın davranışlarını ve iş gereksinimlerini anlamaya odaklanır.
- Yazım Tarzı: TDD’de testler, genellikle teknik düzeyde yazılırken, BDD’de senaryolar iş diliyle yazılır.
Cucumber, Gherkin dilini kullanarak Behavior Driven Development (BDD) Davranış Odaklı Geliştirme metodolojisini destekleyen bir test otomasyon aracıdır. Bu yöntem, yazılımın davranışlarını iş kullanıcıları tarafından anlaşılabilir bir dilde tanımlamaya odaklanır.
Cucumber ve Gherkin ile BDD
Gherkin, Cucumber tarafından kullanılan özel bir sözdizimi ve dilidir.
- Feature Dosyaları Yazma(Scenarios): Gherkin dilini kullanarak, iş analistleri ve ürün sahipleri tarafından anlaşılabilir test senaryoları yazılır. Bu senaryolar, yazılımın belirli bir işlevselliğini veya özelliğini test eder.
- Step Definitions (Adım Tanımlamaları): Her Gherkin adımı için karşılık gelen kod yazılır. Bu kod, testlerin yürütülmesi sırasında belirli eylemleri gerçekleştiren fonksiyonları içerir.
Cucumber’ın Faydaları
- İşbirliği: Gherkin senaryoları, iş analistleri, geliştiriciler ve test mühendisleri arasında daha iyi iletişim ve işbirliği sağlar.
- Anlaşılabilirlik: Doğal dil kullanımı sayesinde, teknik olmayan paydaşlar bile test senaryolarını anlayabilir.
- Otomasyon: Test senaryoları, kolayca otomatikleştirilebilir ve sürekli entegrasyon süreçlerine entegre edilebilir.
Cucumber ve Gherkin, BDD metodolojisinin etkin bir şekilde uygulanmasını sağlar ve yazılımın beklenen davranışlarını doğrulamak için güçlü bir araç sunar.
Özet
- Cucumber: BDD için kullanılan bir test otomasyon aracıdır.
- Gherkin: Cucumber tarafından kullanılan, iş kurallarını ve test senaryolarını tanımlamak için kullanılan bir dildir.
- Given, When, Then: Gherkin dilinde kullanılan temel anahtar kelimelerdir ve senaryoların yapılandırılmasını(steps) sağlar.
Cucumber ve Playwright birlikte kullanılarak, BDD (Behavior Driven Development) senaryolarının yazılması ve yürütülmesi sağlanabilir. Bu iki araç birlikte kullanıldığında, Gherkin dilinde yazılan senaryolar, Playwright ile otomatikleştirilmiş testlere dönüştürülür.
Kurulum ;
- Aqua IDE ile Playwright Kurulumu
Cucumber resmi olarak Javascript dilini tam destekliyor,bizde bu yüzden tam desteğini sağladığı Javascript dili üzerinde Playwright testlerimizi koşacağız.
Javascript ve node.js’i Aqua IDE kurulumunu yapacak,bizim yapmamız gereken diğer kurulum ise cucumber
# NPM
npm install --save-dev @cucumber/cucumber
Şimdi ise Proje içindeki oluşturmamız gereken dosya/klasörleri kuruyoruz
saucedemoAddtoChart_steps.js
Bu kodlarda async () => { ... }
bir arrow function'dır.
Give,Then,When
: Cucumber'da kullanılan adım tanımlama anahtar kelimeleridir.Test senaryolarında adımların nasıl gerçekleştirileceğini belirtir.Cucumber adımını tanımlamak için kullanılan bir arrow function içerir. Arrow function, daha kısa bir sözdizimi sunar ve asenkron işlemleri yönetmek için async
/await
ile birlikte kullanılır
Her Gherkin adımı için karşılık gelen kod yazılır.Give,Then,When
const { When, Then, Given,} = require('@cucumber/cucumber');
const { chromium } = require('playwright');
const assert = require('assert');
const {selectors} = require('../fixtures/saucedemoSelectors')
let browser;
let page;
Given('I am on the login page', async () => {
browser = await chromium.launch();
const context = await browser.newContext();
page = await context.newPage();
await page.goto(selectors.SaucedemoUrl);
});
When('I login with valid credentials', async () => {
await page.fill(selectors.usernameselector, selectors.username);
await page.fill(selectors.passwordselector, selectors.password);
await page.click(selectors.loginButton);
});
Then('I should see the inventory list', async () => {
const isSuccess = await page.isVisible(selectors.inventorylist);
assert.strictEqual(isSuccess, true, 'Inventory list is not visible');
});
When('I logout', async () => {
await page.click(selectors.logoutmenu);
const isLogoutVisible = await page.isVisible(selectors.logoutlink);
if (isLogoutVisible) {
await page.click(selectors.logoutlink);
} else {
throw new Error('Logout link is not visible');
}
});
When('I add the first item to the cart', async () => {
const addToCartButtonSelector = '.inventory_item:first-of-type .btn_inventory';
await page.click(addToCartButtonSelector);
});
Then('the cart badge should display {string}', async (expectedText) => {
const cartBadgeVisible = await page.isVisible(selectors.cartBadgeSelector);
assert.strictEqual(cartBadgeVisible, true, 'Cart badge is not visible');
const cartBadgeText = await page.textContent(selectors.cartBadgeSelector);
assert.strictEqual(cartBadgeText, expectedText, `Cart badge text is not "${expectedText}"`);
});
Then('I should see the item in the cart', async () => {
await page.click(selectors.cartlink);
const cartItemVisible = await page.isVisible(selectors.cartItemSelector);
assert.strictEqual(cartItemVisible, true, 'No product found in the cart');
});
@saucedemo
@addtochart
Feature: 2-Sepete Ekle
Scenario: 2-Successful login and logout
Given I am on the login page
When I login with valid credentials
Then I should see the inventory list
When I logout
Scenario: 2-Add item to cart and verify
Given I am on the login page
When I login with valid credentials
When I add the first item to the cart
Then the cart badge should display "1"
Then I should see the item in the cart
saucedemoAddtoChart.feature
Gherkin dili ile işlevsel testlerin ve kabul testlerinin yazılması
@saucedemo
@addtochart
Bu tag lar sayesinde testlerimizi bu tagları terminalden girerek sadece bu tagları içeren testleri çalıştırabiliyoruz.
npx cucumber-js — tags “@saucedemo”
Test Raporu
Fail test olduğunda bize gerekli açıklamalarıda sağlıyor.
Şimdi testlerimizin cucumber ile entegre halde çalışması için gerekli ayarlarını yapacağız.
playwright.config.js
const { defineConfig, devices } = require('@playwright/test');
/**
* @see https://playwright.dev/docs/test-configuration
*/
module.exports = defineConfig({
testDir: './tests',
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://127.0.0.1:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on',
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
});
cucumber.js
module.exports = {
default: {
tags: process.env.npm_config_TAGS || "",
formatOptions: {
snippetInterface: "async-await"
},
paths: [
"test/features/"
],
//publishQuiet: true,
dryRun: false,
require: [
"test/steps/*.js",
"test/fixtures/*.js",
],
requireModule: [
"ts-node/register"
],
format: [
"progress-bar",
"html:test-results/cucumber-report.html",
"json:test-results/cucumber-report.json",
"rerun:@rerun.txt"
],
parallel: 1
},
rerun: {
formatOptions: {
snippetInterface: "async-await"
},
publishQuiet: true,
dryRun: false,
require: [
"test/steps/*.js",
"test/fixtures/*.js",
],
requireModule: [
"ts-node/register"
],
format: [
"progress-bar",
"html:test-results/cucumber-report.html",
"json:test-results/cucumber-report.json",
"rerun:@rerun.txt"
],
parallel: 2
}
}
Fixture kullanımı
const saucedemoSelectors = {
SaucedemoUrl: 'https://www.saucedemo.com',
usernameselector: '#user-name',
username: 'standard_user',
invalidusername: 'invalid_user',
passwordselector: '#password',
password: 'secret_sauce',
invalidpassword: 'invalid_password',
loginButton: '#login-button',
inventorylist: '.inventory_list',
logoutmenu: '.bm-burger-button',
logoutlink: '#logout_sidebar_link',
loginwrapper: "div[class='login_wrapper-inner']",
error_message: '[data-test="error"]',
error_message_text: 'Epic sadface: Username and password do not match any user in this service',
cartBadgeSelector: '.shopping_cart_badge',
cartlink: '.shopping_cart_link',
cartItemSelector: '.cart_item',
inventoryItemName: '.inventory_item_name',
buttonAddCart:".btn_primary",
inventoryItem: '.inventory_item',
};
module.exports = { selectors: saucedemoSelectors };
module.exports yapmaz isek test sayfasında bu nesneleri tanıyor ama hata veriyor bu yüzden kesinlikle module.exports yapıyoruz.
const {selectors} = require('../fixtures/saucedemoSelectors')
Bu şekilde test datalarınıda tek bir noktadan çekebiliyoruz ve testlerimizde kullanıyoruz.Daha sonra element seçicilerde değişiklik olursa bu fixture dan dataları değiştiriyoruz,buda bize testlerin bakımında kolaylık sağlıyor,özellikle aynı element seçici çok fazla testte kullanılıyor veya çok adımda kullanıyor ise sadece fixture nesnesindeki kaynaktan değiştirip tüm testlerimizin datasını güncellemiş oluyoruz.
Bileşenin hiyerarşik ilişkisi ;
- Gherkin: Gherkin, doğal dilde yazılan ve iş gereksinimlerini, kullanıcı davranışlarını tanımlayan bir dil formatıdır. BDD (Behavior-Driven Development) metodolojisi için kullanılır ve Cucumber gibi araçlar tarafından desteklenir.
- Cucumber: Cucumber, Gherkin dilinde yazılan senaryoları otomatize eden bir BDD aracıdır. Senaryoları test adımlarına bağlar ve bu adımları gerçekleştirmek için çeşitli test otomasyon araçları (örneğin, Playwright) ile entegre edilir.
- Playwright: Playwright, tarayıcı tabanlı uygulamaları otomatize etmek için kullanılan güçlü bir test otomasyon aracıdır. Chromium, Firefox ve WebKit tabanlı tarayıcıları destekler ve tarayıcıda kullanıcı etkileşimlerini (sayfa gezintisi, form doldurma, tıklama vb.) otomatize etme yeteneği sağlar.
Umarım bu 3 önemli aracın işlevlerini tamamen kavrayıp testlerinizde gerektiğinde uygularsınız.