टेस्ट डेटा, फ़िक्स्चर और हुक्स

Automated test को एक तय शुरुआती हालत चाहिए: एक मौजूद customer, एक item वाला order, browser में खुला page। Test data वे values हैं जो test इस्तेमाल करता है; fixture दोबारा इस्तेमाल होने वाला setup है जो test की ज़रूरत की state बनाता है, उसे test को देता है और बाद में हटा देता है; hooks वे functions हैं जिन्हें test runner tests से पहले या बाद में अपने-आप बुलाता है, जैसे beforeEach और afterEach। मसलन, checkout test को fixture से एक नया customer मिलता है, beforeEach hook cart खोलता है, और test ख़त्म होने पर fixture customer को delete कर देता है, test pass हो या fail।

Parameterised, यानी data-driven, tests उल्टी समस्या हल करते हैं: एक ही test body data table की हर row के लिए एक बार चलती है, तो छह discount codes बिना code की छह copies के छह reported tests बन जाते हैं। Test data वाले lesson में आपने सीखा कि कौन-सी values चुननी हैं; यह lesson बताता है कि automated tests में वे values कहाँ रहती हैं, और कैसे बनाई और साफ़ की जाती हैं।

यह क्यों ज़रूरी है

कई unreliable automated suites product की वजह से नहीं, state की वजह से fail होती हैं। एक test अकेले pass होता है और पूरे run में fail, क्योंकि पहले वाले test ने shared account बदल दिया; Monday को run fail होता है क्योंकि test जिस coupon पर निर्भर था वह expire हो गया; हज़ारों runs के बचे हुए orders एक list page को इतना धीमा कर देते हैं कि उसके tests timeout हो जाते हैं। Suite का setup और cleanup तय करता है कि लाल result का मतलब defect है या सिर्फ़ noise, और noise team को लाल results नज़रअंदाज़ करना सिखा देता है।

Setup maintenance की लागत भी तय करता है। Sign-in flow बदले तो fixture एक जगह है जिसे update करना है; copy किए गए बीस setup blocks बीस जगहें हैं। Data-driven tests में नया case एक row जोड़कर जुड़ जाता है, और पढ़ने लायक table reviewer या product owner को code पढ़े बिना cases जाँचने देती है।

Automated test में test data कहाँ रहता है

Test runner tests को बिना निगरानी, किसी भी क्रम में और अक्सर parallel में चलाता है, इसलिए test जिस भी value पर निर्भर है वह ऐसी जगह से आनी चाहिए जिस पर test का नियंत्रण हो। जो test चुपचाप किसी shared environment में हाथ से बनाए गए record पर निर्भर है, वह उस दिन fail होगा जिस दिन वह record बदला या delete हुआ, और वह failure product defect जैसा दिखेगा।

Data कहीं भी रहे, दो नियम लागू होते हैं। Test उस data का मालिक है जिसे वह बदलता है: सिर्फ़ read-only reference data, जैसे countries की list या ऐसा product catalogue जिसे कोई test नहीं बदलता, share किया जा सकता है। और जिस field को unique होना है उसे हर run में unique value मिलती है, जैसे sara+${runId}@example.com, ताकि दूसरा run या parallel worker "already exists" से fail न हो।

Data ख़ुद चार जगह रह सकता है; चुनें इस आधार पर कि test पढ़ने वाले को क्या दिखना चाहिए।

  • Test के अंदर inline: वे एक-दो values जो test को समझाती हैं, जैसे "rejects a zero quantity" नाम के test में quantity: 0। जो value मायने रखती है उसे assertion के पास दिखता रखें।
  • Builder या factory function: makeCustomer({ country: "JO" }) समझदार defaults के साथ पूरा valid record लौटाता है, और test सिर्फ़ वही field बदलता है जिसके बारे में वह है। कोई नया mandatory field आए तो factory एक बार बदलें।
  • Data file: repository में tests के बगल में CSV या JSON table, जब कई cases एक ही test body share करते हों। इसे code की तरह review और version किया जाता है।
  • Test से पहले बनाई गई state: वे records जिनका मौजूद होना ज़रूरी है, screens पर click करके नहीं बल्कि API या seed script से बनाए जाते हैं, क्योंकि clicking धीमी है और ऐसी वजहों से fail होती है जिनसे test का कोई लेना-देना नहीं।

आज़माएँ: टेस्ट डेटा फ़ैक्टरी आज़माएँ: UUID जनरेटर

Hooks: वह code जिसे runner tests से पहले और बाद में बुलाता है

ज़्यादातर runners चार hooks देते हैं। beforeAll file या group के पहले test से पहले एक बार चलता है, beforeEach हर test से पहले, afterEach हर test के बाद और afterAll आख़िरी test के बाद एक बार। Jest और Vitest ठीक यही नाम इस्तेमाल करते हैं; Playwright Test इन्हें test.beforeEach वगैरह लिखता है; JUnit 5 annotations @BeforeAll, @BeforeEach, @AfterEach और @AfterAll इस्तेमाल करता है। pytest साधारण setup और teardown functions भी support करता है, लेकिन उसका आम औज़ार fixture है, जो अगले section में समझाया गया है।

हर test के लिए क्रम है: beforeEach hooks, फिर test body, फिर afterEach hooks। Nested groups में बाहरी group का beforeEach अंदर वाले group के beforeEach से पहले चलता है। सबसे ज़रूरी बात यह है कि after-hooks test fail होने पर भी चलते हैं। Fail हुआ assertion test body को उसी line पर रोक देता है, इसलिए body की आख़िरी lines में लिखा cleanup कभी नहीं चलता, जबकि afterEach में रखा cleanup चलता है।

जिस state को tests बदलते हैं उसके लिए beforeEach इस्तेमाल करें, ताकि हर test नए सिरे से शुरू हो। beforeAll सिर्फ़ ऐसे महँगे setup के लिए रखें जिसे tests पढ़ते हैं पर कभी बदलते नहीं, जैसे stub server चालू करना; एक बार बना और कई tests द्वारा बदला गया mutable data result को इस पर निर्भर बना देता है कि tests किस क्रम में चले। Playwright Test में beforeAll हर worker process में एक बार चलता है, और किसी test के fail होने के बाद उसकी जगह आए नए worker में फिर से चलता है, इसलिए उसे दोबारा चलना सुरक्षित होना चाहिए।

import { test, expect } from '@playwright/test';

test.describe('saved addresses', () => {
  const created: string[] = [];              // ids of addresses these tests created

  test.beforeEach(async ({ page }) => {
    await page.goto('/account/addresses');   // every test starts on the same page
  });

  test.afterEach(async ({ request }) => {      // request: an HTTP client for the API
    for (const id of created) {              // runs even when the test failed
      await request.delete(`/api/addresses/${id}`);
    }
    created.length = 0;
  });

  test('lists an address added through the API', async ({ page, request }) => {
    const res = await request.post('/api/addresses', { data: { city: 'Riyadh' } });
    created.push((await res.json()).id);
    await page.reload();
    await expect(page.getByText('Riyadh')).toBeVisible();
  });
});

Fixtures: वह setup जिसे test नाम से माँगता है

Fixture तीन चीज़ें साथ रखता है: setup, वह value जो test को मिलती है, और teardown। Test setup code ख़ुद बुलाने के बजाय fixture को उसके नाम से माँगता है। Playwright Test में page (browser का एक page) और request (API को सीधे call करने वाला HTTP client) built-in fixtures हैं, और अपने fixtures test.extend से जोड़े जाते हैं: await use(value) से पहले का code setup है, test use के दौरान चलता है, और उसके बाद का code teardown है, जो test pass हो या fail, चलता है। pytest में fixture @pytest.fixture से marked function है जिसे test अपने parameter में उसका नाम लिखकर माँगता है; वह value yield से देता है, और yield के बाद का code teardown है।

Hooks की तुलना में fixtures on demand चलते हैं: customer बनाने की लागत सिर्फ़ वे tests चुकाते हैं जो customer माँगते हैं। वे compose होते हैं: order fixture customer fixture माँग सकता है, और teardown उल्टे क्रम में चलता है, तो order अपने customer से पहले delete होता है। उनका scope होता है: default रूप से हर test के लिए, या ज़्यादा व्यापक रूप से shared, Playwright में हर worker के लिए या pytest में हर module या session के लिए, उन महँगी चीज़ों के लिए जिन्हें tests सिर्फ़ पढ़ते हैं। Playwright Test में fixture default रूप से lazily set up होता है, ठीक उस पहले hook या test से पहले जो उसे माँगता है: beforeEach hook जिस page को इस्तेमाल करता है वह उस hook के चलने से पहले तैयार होता है, जबकि जिस customer को सिर्फ़ test body माँगती है वह beforeEach hooks के बाद बनता है। Test-scoped fixtures afterEach hooks के बाद tear down होते हैं।

जो values मायने रखती हैं उन्हें दिखता रखें। Fixture को यह छिपाना चाहिए कि customer कैसे बनता है, यह नहीं कि test को कैसा customer चाहिए; अगर test customer के country जैसी किसी detail पर निर्भर है, तो उसे साफ़-साफ़ pass करें या साफ़ नाम वाला अलग fixture बनाएँ।

Playwright Test में fixture उस पहले hook या test body से ठीक पहले set up होता है जो उसे माँगता है और afterEach hooks के बाद tear down होता है, और assertion fail होने पर भी afterEach और teardown चलते हैं।
  1. 1beforeAll hookFile या group के पहले test से पहले, हर worker में एक बार; सिर्फ़ ऐसा setup जिसे tests पढ़ते हैं, बदलते नहींएक बार
  2. 2page fixture setupपहले set up होता है क्योंकि beforeEach hook page माँगता है
  3. 3beforeEach hookवह page खोलता है जहाँ से हर test शुरू होता है
  4. 4customer fixture setupइसे सिर्फ़ test body माँगती है, इसलिए यह अब set up होता है: await use() से पहले का code API से नया customer बनाता है
  5. 5Test bodyFixture से मिले customer के साथ actions और assertions

    शाखा: Assertion fail: body उसी line पर रुक जाती है, और steps 6 और 7 फिर भी चलते हैंफ़ेल

  6. 6afterEach hookTest pass हो या fail, चलता है, जैसे test के record किए ids delete करने के लिए
  7. 7Fixture teardownSetup के उल्टे क्रम में: use() के बाद का code customer delete करता है, फिर page बंद होता है
  8. 8afterAll hookFile या group के आख़िरी test के बादएक बार

चरण 2–7 के दौरान हर test के लिए दोहराया जाता है

क्रम Playwright Test के documentation के अनुसार है। Jest, Vitest और JUnit यही चार hooks चलाते हैं; pytest ये steps fixtures से बनाता है।

// fixtures.ts
import { test as base, expect } from '@playwright/test';
import { randomUUID } from 'node:crypto';

type Customer = { id: string; email: string };

export const test = base.extend<{ customer: Customer }>({
  customer: async ({ request }, use) => {
    // setup: a fresh customer for this test only
    const email = `sara+${randomUUID()}@example.com`;
    const res = await request.post('/api/customers', { data: { email } });
    const customer: Customer = await res.json();

    await use(customer);                     // the test runs here

    // teardown: runs after the test, passed or failed
    await request.delete(`/api/customers/${customer.id}`);
  },
});
export { expect };

// orders.spec.ts
import { test, expect } from './fixtures';

test('a new customer has no orders', async ({ request, customer }) => {
  const res = await request.get(`/api/customers/${customer.id}/orders`);
  expect(await res.json()).toEqual([]);
});

आज़माएँ: फ़ेक यूज़र जनरेटर

Cleanup: environment को वैसा ही छोड़ें जैसा मिला था

बचा हुआ data बेनुकसान नहीं होता। वह उन lists और search results को भर देता है जिन पर दूसरे tests assert करते हैं, unique constraints से टकराता है, और shared test environment में manual testers को उलझाता है। जो भी test कुछ बनाता है उसे उसे हटाने की योजना चाहिए, या ऐसा environment जो इस्तेमाल के बाद फेंक दिया जाए।

  • Cleanup को after-hook या fixture teardown में रखें, कभी सिर्फ़ test body के आख़िर में नहीं।
  • ठीक वही delete करें जो test ने बनाया, id से। कभी "example.com पर ख़त्म होने वाले email वाले हर customer को delete करो" जैसी broad query से cleanup न करें: shared environment में यह दूसरों का data और parallel runs का data भी मिटा देती है।
  • Setup steps अलग-अलग रखें, ताकि एक fail हुआ step उससे पहले वाले steps का teardown न छोड़ दे; pytest documentation इसी वजह से हर fixture में एक ही state बदलने वाला action रखने की सलाह देता है।
  • Teardown को पहले से हट चुके record के प्रति सहनशील बनाएँ, जैसे जब test ने ख़ुद उसे delete कर दिया हो, लेकिन cleanup की किसी और failure को दबाने के बजाय report करें।
  • जहाँ setup इजाज़त दे, ख़ुद मिटने वाला data चुनें: उन integration tests में जो code under test के साथ एक ही database connection share करते हैं, हर test के बाद rollback होने वाला database transaction; हर run के लिए नया container या reset होने वाला environment; या हर run के लिए अलग tenant।
  • बनाए गए data पर run prefix लगाएँ, जैसे AT-20261002-0412-, ताकि एक scheduled job crash हुए runs का छोड़ा हुआ data ढूँढकर हटा सके।

Worked example: एक test, discount codes की एक table

Requirement: "Code SAVE10 200.00 SAR या उससे ज़्यादा के orders पर 10% छूट देता है, और उससे कम पर minimum-order error के साथ reject होता है। Codes case-sensitive नहीं हैं। Expired या unknown code total नहीं बदलता और error दिखाता है।" छह लगभग एक जैसे tests लिखना वही steps छह बार copy करना है। Data-driven test एक test body रखता है और cases को एक table में ले जाता है; ISTQB glossary data-driven testing को ऐसी scripting technique बताती है जिसमें data files test data और expected results रखती हैं।

हर बड़ा runner यह support करता है। Jest और Vitest में test.each(rows)("$case", fn) हर row के लिए एक test बनाता है और case की value उसके title में डालता है। pytest में @pytest.mark.parametrize("row", rows) यही करता है, और pytest.param(row, id=...) हर case को नाम देता है। JUnit 5 में @ParameterizedTest के साथ @CsvFileSource(resources = "/discount-cases.csv", numLinesToSkip = 1) CSV file से rows पढ़ता है और header line छोड़ देता है। Playwright Test में test.each नहीं है; उसकी documentation loop में हर row के लिए एक test() बनाती है, और हर title unique होना चाहिए।

नीचे की table में सिर्फ़ inputs और expected results हैं, और हर expected total requirement से हाथ से निकाला गया है। Test file पढ़ता है और हर row को fixture से मिले नए cart के साथ चलाता है।

  • हर row को एक name column दें। तब report "row 5 failed" की जगह "expired code failed" कहती है।
  • Values ठीक वैसे लिखें जैसे system दिखाता है: 200.00, 200 नहीं। CSV में जिस value में comma, double quote या line break हो उसे double quotes में रखना चाहिए, और उसके अंदर का double quote दो बार लिखा जाता है (RFC 4180)।
  • Pitfall, एक विशाल table: हर feature के columns वाली 200 rows की file review नहीं हो सकती, और हर बदलाव उसे छूता है। हर rule की अपनी table रखें, इतनी छोटी कि एक मिनट में पढ़ी जा सके, और rows का ढेर लगाने के बजाय boundary value analysis जैसी test design techniques से rows चुनें।
  • Pitfall, data में छिपा test logic: click_apply_twice या skip_login जैसे columns table को ऐसा program बना देते हैं जिसे कोई test नहीं करता। जिन rows को अलग steps चाहिए, वे अलग tests हैं। यही बात उन expected values पर लागू होती है जिन्हें test product के ही formula से calculate करता है: तब formula का defect दोनों तरफ़ छिप जाता है।
data/discount-cases.csv
case,code,cart_total,expected_total,error
valid code,SAVE10,250.00,225.00,
lower-case code,save10,200.00,180.00,
minimum order exactly,SAVE10,200.00,180.00,
just below minimum,SAVE10,199.99,199.99,MIN_ORDER
expired code,OLD5,200.00,200.00,EXPIRED
unknown code,NOPE10,200.00,200.00,NOT_FOUND

test_discounts.py  (pytest: one test body, six reported tests)
import csv
from decimal import Decimal
import pytest

def load_cases(path):
    with open(path, newline="", encoding="utf-8") as f:
        return [pytest.param(row, id=row["case"]) for row in csv.DictReader(f)]

@pytest.mark.parametrize("row", load_cases("data/discount-cases.csv"))
def test_discount_code(cart, row):           # cart: a fixture, fresh per test
    cart.set_total(Decimal(row["cart_total"]))
    result = cart.apply_code(row["code"])
    assert result.total == Decimal(row["expected_total"])
    assert result.error == (row["error"] or None)

आज़माएँ: CSV डेटासेट जनरेटर आज़माएँ: CSV से JSON

आम गलतियाँ

  • Cleanup को test body की आख़िरी lines में लिखना, जहाँ पहला fail हुआ assertion उसे छोड़ देता है।
  • beforeAll में data एक बार बनाना और कई tests को उसे बदलने देना, जिससे test का pass या fail इस पर निर्भर हो जाता है कि उससे पहले कौन-से tests चले।
  • Shared environment में हाथ से बनाए records पर निर्भर रहना, जैसे "customer 1001", जिसे कोई भी बदल या delete कर सकता है।
  • Unique होने वाले field के लिए test@example.com जैसी fixed value इस्तेमाल करना, जिससे दूसरा run या parallel worker "already exists" से fail होता है।
  • ज़रूरी values को fixture के अंदर छिपा देना, जिससे पढ़ने वाला test("works", async ({ setup }) => …) देखता है और नहीं जान पाता कि test को क्या चाहिए या वह क्या जाँचता है।
  • Expected result तय करने वाले inputs के लिए random values बनाना और उन्हें log न करना, जिससे failure reproduce नहीं हो पाता।

QA का नज़रिया

जब आप कोई automated test review करें, अपना या किसी developer का, तो उसके data के बारे में चार सवाल पूछें। यह कहाँ से आता है? इसे और कौन बदल सकता है? Test के बाद इसका क्या होता है? क्या यह test अकेले, लगातार दो बार और ख़ुद के साथ parallel में चल सकता है? जो test इनमें से किसी सवाल पर अटकता है, वह किसी दिन ऐसी वजह से fail होगा जिसका product से कोई संबंध नहीं। Developers के साथ जल्दी तय करें कि tests data कैसे बनाते और हटाते हैं: test-only API endpoints या seed scripts जो कभी production में deploy नहीं होते, unique values की conventions, और shared environments कितनी बार reset होते हैं।

Data-driven tables वह जगह हैं जहाँ tester सबसे ज़्यादा value जोड़ता है। Rows test design techniques से आती हैं, जैसे equivalence partitioning, boundary value analysis और decision tables; हर technique एक rule को कुछ meaningful rows में बदलती है। Product owner अच्छे नाम वाली table को code पढ़े बिना review कर सकता है। जब कोई row fail हो, तो bug report में row, उसका data और fixtures द्वारा बनाए गए ids लिखें, ताकि developer ठीक वही state reproduce कर सके।

अभ्यास

एक कमज़ोर coupon test को refactor करें

आपका काम

नीचे का test जल्दबाज़ी में लिखा गया था और CI में लगभग हफ़्ते में एक बार fail होता है। इसे पढ़ें और इसके data, setup और cleanup की हर समस्या लिखें। फिर बताएँ कि इसकी जगह आप कौन-से fixtures, hooks और data table इस्तेमाल करेंगे, और run को कितने tests report करने चाहिए।

सामग्री
test('coupon tests', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('qa.shared@example.com');
  await page.getByLabel('Password').fill(process.env.SHARED_PASSWORD!);
  await page.getByRole('button', { name: 'Sign in' }).click();
  const res = await page.request.post('/api/orders', { data: { total: '200.00' } });
  const order = await res.json();

  for (const c of [
    { code: 'SAVE10', expected: '180.00', applyTwice: false },
    { code: 'save10', expected: '180.00', applyTwice: true },
    { code: 'OLD5', expected: 'error', applyTwice: false },
  ]) {
    await page.goto(`/orders/${order.id}`);
    await page.getByLabel('Coupon').fill(c.code);
    await page.getByRole('button', { name: 'Apply' }).click();
    if (c.applyTwice) await page.getByRole('button', { name: 'Apply' }).click();
    if (c.expected === 'error') await expect(page.getByRole('alert')).toBeVisible();
    else await expect(page.getByTestId('total')).toHaveText(c.expected);
  }

  await page.request.delete(`/api/orders/${order.id}`);
});
चरण
  1. वह data ढूँढें जिसका मालिक test नहीं है, और उसे और कौन बदल सकता है।
  2. वह cleanup ढूँढें जो छूट सकता है, और वह state जो एक case से अगले case में रिसती है।
  3. Data में छिपा logic ढूँढें।
  4. Replacement design करें: fixtures उनके teardown के साथ, कोई hook, और table उसके columns और rows के साथ।
मॉडल उत्तर दिखाएँ
मॉडल उत्तर

जिस data का मालिक नहीं: shared account qa.shared@example.com को कोई भी दूसरा test, tester या parallel run इस्तेमाल, बदल या lock कर सकता है। इसकी जगह customer fixture रखें जो API से unique customer बनाए और teardown में delete करे, और login form की जगह API या saved session से sign in करें; login form का अपना अलग test होना चाहिए।

छूटने वाला cleanup और रिसती state: body के आख़िर का DELETE assertion fail होने पर कभी नहीं चलता, इसलिए orders जमा होते जाते हैं। तीनों cases एक ही order share करते हैं: SAVE10 लगने के बाद दूसरा case पहले से discounted order से शुरू होता है, और पहला case fail हो तो बाकी चलते ही नहीं। Run तीन cases के लिए एक ही test report करता है।

छिपा logic: applyTwice और magic value "error" बदल देते हैं कि test क्या करता है। "Code दो बार लगाने पर भी एक ही discount रहता है" अपना अलग test है, और expected error अपने column में specific error के साथ होना चाहिए, generic alert check के रूप में नहीं। Title coupon tests कुछ नहीं बताता; हर नया test अपने case का नाम बताता है।

Replacement: customer fixture (create, फिर use, फिर delete), और createOrder fixture जो customer माँगता है और test को एक function देता है: वह row के total से order बनाता है और उसका id record करता है, और उसका teardown, customer fixture के customer delete करने से पहले, हर recorded order delete करता है। beforeEach की ज़रूरत नहीं: हर test order बनाने के बाद अपना order page ख़ुद खोलता है, और यहाँ hook वही एक step छिपा देगा जो अलग है। Table के columns case, code, cart_total, expected_total और error हैं, rows जैसे valid code, lower-case code, minimum order exactly, just below minimum, expired code और unknown code, और एक loop हर row के लिए unique title वाला एक test बनाता है। तब run हर row के लिए एक test, और साथ में अलग "applied twice" test report करता है, यानी इन छह rows के साथ सात tests, और हर test अपने नए order से शुरू होता है।

अक्सर पूछे जाने वाले सवाल

Hooks इस्तेमाल करूँ या fixtures?

अगर आपके framework में fixtures हैं, जैसे Playwright Test और pytest में, तो हर उस चीज़ के लिए उन्हें इस्तेमाल करें जो value देती है और जिसे teardown चाहिए, जैसे customer या order: वे सिर्फ़ उन tests के लिए चलते हैं जो उन्हें माँगते हैं और setup व cleanup को साथ रखते हैं। Hooks उन साधारण steps के लिए ठीक हैं जिनकी file के हर test को ज़रूरत है, जैसे एक ही page खोलना। Jest, Vitest और JUnit में hooks के साथ helper या factory functions यही काम करते हैं।

Data file CSV हो या JSON?

CSV flat tables के लिए ठीक है: spreadsheet में खुलती है, non-programmer उसे review कर सकता है, और उसके बदलाव diff में साफ़ दिखते हैं, लेकिन हर value text होती है और comma वाली values को quotes चाहिए। JSON nested data, numbers, booleans और null जैसी typed values, और API request bodies के लिए ठीक है। दोनों हालात में file को repository में उन tests के बगल में रखें जो उसे इस्तेमाल करते हैं।

क्या random test data अच्छा विचार है?

Random values uniqueness के लिए अच्छी हैं, जैसे emails और ids जो आपस में टकराने नहीं चाहिए। जो values expected result तय करती हैं, उनके लिए fixed, सोच-समझकर चुना data बेहतर है। अगर ज़्यादा coverage के लिए inputs generate करते हैं, तो values या random seed log करें ताकि fail हुआ run ठीक वैसे ही दोहराया जा सके।

संदर्भ

  • ISTQB GlossaryISTQBटेस्टिंग शब्दों की मानक परिभाषाएँ — टेस्ट केस, रिग्रेशन टेस्टिंग, सेवेरिटी, प्रायोरिटी, बाउंड्री वैल्यू एनालिसिस आदि।
  • Playwright DocumentationMicrosoft (Playwright)Playwright का आधिकारिक दस्तावेज़ — Chromium, WebKit और Firefox चलाने वाला end-to-end टेस्ट फ़्रेमवर्क।
  • Eradicating Non-Determinism in Tests (Martin Fowler)martinfowler.com · 2011flaky टेस्ट सूट का मूल्य क्यों नष्ट करते हैं, उनके आम कारण (isolation, asynchrony, remote services, समय, resource leak) और जवाब के रूप में quarantine।
  • RFC 4180: Common Format and MIME Type for Comma-Separated Values (CSV) FilesIETF · 2005CSV के आम नियम: कॉमा सेपरेटर, CRLF लाइन एंड, और कॉमा, कोट या लाइन ब्रेक वाले फ़ील्ड की क्वोटिंग।

Mutqan tools से अभ्यास करें

कस्टम कॉलम, डेटा टाइप, पंक्ति संख्या और डिलिमिटर के साथ CSV फ़ाइलें जनरेट करें।

टेस्ट डेटा

CSV या TSV डेटा को JSON ऑब्जेक्ट के ऐरे में बदलें।

JSON और डेटा

सिंथेटिक टेस्ट डेटा की एक ही जगह पर फ़ैक्टरी: users, customers, companies, पते, संख्याएँ, तारीख़ें और स्ट्रिंग — JSON, CSV, SQL या XML में।

टेस्ट डेटा

टेस्ट अकाउंट के लिए फ़ेक यूज़र रिकॉर्ड (नाम, username, ईमेल, पासवर्ड, avatar seed, role) जनरेट करें।

टेस्ट डेटा

UUID v4 (रैंडम) और v7 (समय-क्रमित) पहचानकर्ता थोक में बनाएँ और मौजूदा UUID वैलिडेट करें।

यूटिलिटीज़

JSON सिंटैक्स वैलिडेट करें और गलतियों की सटीक जगह के साथ सुधार के उपयोगी सुझाव पाएँ।

JSON और डेटा

और गहराई से

इस topic में आपकी प्रगति

QA रोडमैप का हिस्सा