آخرین بازبینی فنی: مرداد ۱۴۰۵

یک کپی از دیتابیس Production شاید در چند دقیقه محیط تست را «واقعی» کند؛ اما همان کپی می‌تواند شماره تماس، نشانی، سابقه خرید، Token یا متن آزاد کاربران را به محیطی ببرد که دسترسی و پایش ضعیف‌تری دارد. از آن طرف، چند نام و ایمیل تصادفی هم لزوماً داده تست خوب نیست: ممکن است Constraintهای دامنه، توزیع مبلغ‌ها، روابط بین جدول‌ها و سناریوهای نادر را نابود کند. بنابراین پرسش درست این نیست که داده تست واقعی بهتر است یا مصنوعی؛ پرسش این است: «برای کدام هدف تست، چه Fidelity لازم داریم و کم‌ریسک‌ترین راه تأمین آن چیست؟»

در این راهنما داده Production، Masked، Pseudonymized، Anonymized و Synthetic را دقیق تفکیک می‌کنیم؛ سپس با یک ماتریس تصمیم، Data Contract، کنترل‌های حریم خصوصی و مثال اجرایی فروشگاه ایرانی نشان می‌دهیم چگونه یک Portfolio ترکیبی و قابل‌ممیزی بسازیم.

پاسخ کوتاه: برای Unit، Component، Regression و بیشتر CIها، داده مصنوعی Rule-based و قطعی انتخاب پیش‌فرض خوبی است. برای Migration، تحلیل الگوی واقعی یا باگ وابسته به داده، شاید یک Subset حداقلی و کنترل‌شده لازم باشد؛ اما Masking ساده مترادف Anonymization نیست. برای Performance، داده مصنوعی حجیم را با آمار تجمیعی Production کالیبره کنید، نه با کپی رکوردهای کاربران. داده Synthetic مبتنی بر مدل نیز خودکار «بی‌خطر» یا «منطبق با قانون» نمی‌شود و باید Utility و Privacy آن جدا ارزیابی شود.

این مقاله چه مسئله‌ای را حل می‌کند؟

راهنمای جامع مدیریت داده تست (TDM) مالک چرخه کامل Strategy، Provisioning، Refresh و Governance است. این صفحه روی یک تصمیم باریک‌تر تمرکز دارد: برای هر Test Objective از داده واقعی، تبدیل‌شده، مصنوعی یا ترکیبی استفاده کنیم؟

کلمات کلیدی فرعی این Intent عبارت‌اند از داده مصنوعی برای تست نرم‌افزار، Production Data در محیط تست، Data Masking، ناشناس‌سازی داده و مقایسه Synthetic Data با Real Data. نتیجه مطلوب نیز خرید یک ابزار خاص نیست؛ یک تصمیم قابل‌ردیابی با Owner، معیار پذیرش و تاریخ انقضاست.

اول واژه‌ها را از هم جدا کنیم

بسیاری از تصمیم‌های اشتباه از آنجا شروع می‌شوند که هر داده غیرجعلی را «واقعی» و هر داده دست‌کاری‌شده را «ناشناس» می‌نامیم. در Data Inventory نوع Dataset را صریح ثبت کنید.

نوع داده تعریف عملی ریسک اصلی کاربرد رایج
Production/Operational رکوردی که از سامانه عملیاتی و فعالیت شخص/کسب‌وکار واقعی آمده است افشای هویت، داده مالی/تجاری، Secret و Side Effect فقط نیازهای توجیه‌شده و کنترل‌شده
Subset بخش کوچک‌تری از داده Production کم‌شدن حجم به معنی حذف حساسیت نیست Migration rehearsal یا بازتولید مسئله داده‌محور
Masked/Transformed مقادیر با Redaction، Substitution، Shuffle، Tokenization یا Generalization تغییر کرده‌اند شناسه‌های غیرمستقیم، متن آزاد یا روابط ممکن است هویت را برگردانند آزمون سازگاری Schema/رابطه در Enclave کنترل‌شده
Pseudonymized شناسه با Pseudonym جایگزین شده و با اطلاعات جداگانه امکان اتصال مجدد وجود دارد Mapping و Quasi-Identifierها همچنان حساس‌اند ردیابی طولی محدود با کنترل دسترسی
Anonymized ریسک شناسایی در Context تعریف‌شده به حد قابل‌قبول رسیده است تغییر فناوری، داده کمکی یا گیرنده می‌تواند Risk را عوض کند تحلیل/اشتراک پس از ارزیابی رسمی
Rule-based Synthetic از Schema، Rule و Scenario ساخته می‌شود و از رکورد شخص واقعی مشتق نیست Fidelity ناکافی یا تولید مقصد ظاهراً واقعی CI، Regression، Boundary و حالت‌های نادر
Model-based Synthetic مدل از الگو یا توزیع داده مرجع می‌آموزد و رکوردهای جدید می‌سازد Memorization، Membership/Attribute Inference، Bias و افت Utility تحلیل یا داده حجیم پس از Privacy/Utility Evaluation

NIST SP 800-188 هشدار می‌دهد هر ابزاری که اطلاعات شخصی را Mask می‌کند الزاماً De-identification کافی انجام نمی‌دهد. همچنین در تعریف رسمی GDPR، Pseudonymization به اطلاعات جداگانه برای Attribution دوباره وابسته است؛ بنابراین «اسم را Hash کردیم» مجوز آزادکردن Dataset نیست.

Production-like با Production یکسان نیست

Test Data باید در ابعادی که برای Test Objective مهم است شبیه Production باشد: Schema، Cardinality، Distribution، Correlation، State، Volume، Encoding یا History. هیچ الزامی نیست هویت اشخاص هم واقعی باشد. برای تست مالیات، رابطه استان و نوع کالا مهم است؛ نام واقعی خریدار معمولاً Utility اضافه نمی‌کند.

Synthetic با Random مترادف نیست

Generator که هر فیلد را مستقل Random می‌کند ممکن است سفارش بدون مشتری، کد تخفیف فعال برای کالای ممنوع یا تاریخ تحویل پیش از پرداخت بسازد. Synthetic خوب Rule، Constraint، Distribution، Scenario Label و Oracle دارد. راهنمای تولید داده تست الگوهای Factory، Fixture و Property-based را عمیق‌تر توضیح می‌دهد.

پنج باور خطرناک درباره داده واقعی و مصنوعی

۱. «ریسک داده مصنوعی صفر است»

اگر داده فقط از Ruleهای مستقل و غیرشخصی ساخته شده باشد، ریسک حریم خصوصی معمولاً بسیار کمتر است؛ ولی Model-based Synthetic ممکن است الگو یا Outlier داده مرجع را افشا کند. راهنمای رسمی ICO درباره Privacy-Enhancing Technologies به Model Inversion، Membership Inference و Attribute Disclosure اشاره می‌کند. Synthetic بودن یک ویژگی منشأ است، نه گواهی Privacy.

۲. «Synthetic یا Masked یعنی انطباق خودکار»

انطباق به Jurisdiction، Purpose، منشأ، امکان شناسایی، دسترسی، Retention و قراردادها وابسته است. اصول رسمی European Data Protection Board برای GDPR شامل Purpose Limitation، Data Minimisation، Storage Limitation و Safeguard فنی/سازمانی است. این منبع فقط وقتی دامنه حقوقی آن بر سازمان شما اعمال می‌شود الزام‌آور است؛ تیم ایرانی باید قانون، قرارداد، الزامات بخشی و انتقال برون‌مرزی مربوط به خودش را با مسئول حقوقی/حریم خصوصی تعیین کند.

۳. «داده واقعی به‌طور طبیعی پوشش کامل دارد»

Production فراوانی رخدادهای گذشته را نشان می‌دهد، نه همه Ruleها و Failureهای آینده را. ممکن است مقدار مرزی، حساب مسدود، موجودی صفر یا کوپن منقضی در Sample نباشد. داده Synthetic هدفمند برای تحلیل مقدار مرزی و Partitionهای هم‌ارزی پیچیده قابل‌کنترل‌تر است.

۴. «UAT حتماً به داده واقعی نیاز دارد»

کاربر کسب‌وکار به Workflow، اصطلاحات، Role، State و نتیجه واقع‌گرایانه نیاز دارد؛ نه لزوماً هویت مشتری واقعی. Scenarioهای Curated و Synthetic در بسیاری از UATها کافی‌اند. اگر Migration یا رفتار تاریخی خاص فقط با داده واقعی سنجیده می‌شود، Subset حداقلی را در محیط محدود و با Approval استفاده کنید.

۵. «AI خودش داده امن و باکیفیت تولید می‌کند»

روش Generative ممکن است Correlation را بهتر تقلید کند، اما Ruleهای کسب‌وکار، Bias، Rare Case، Leakage و Drift همچنان باید سنجیده شوند. نام مدل یا شباهت بصری چند ردیف، Evidence کافی نیست. NIST در PETs Testbed دقیقاً Trade-off میان Privacy، Utility و Artifact/Bias روش‌های De-identification و Synthesis را موضوع ارزیابی می‌داند.

چارچوب انتخاب: Objective → Fidelity → Risk → Strategy

گام ۱: Test Objective را یک‌خطی کنید

«تست Checkout» بیش از حد کلی است. بنویسید: «می‌خواهیم ثابت کنیم سفارش با موجودی صفر Reject می‌شود»، «Migration رابطه مشتری و سفارش را حفظ می‌کند» یا «p95 جست‌وجو در ۲۰۰ درخواست بر ثانیه از SLO عبور نمی‌کند». Data Strategy باید پاسخ همین ادعا را ممکن کند.

گام ۲: Fidelity لازم را بُعدبه‌بُعد تعیین کنید

  • Structural: نوع، طول، Nullable، Schema و Encoding؛
  • Relational: Foreign Key، Cardinality و Dependency بین موجودیت‌ها؛
  • Behavioral: State و Ruleهایی که مسیر سیستم را تغییر می‌دهند؛
  • Statistical: Distribution، Correlation، Seasonality و Outlier؛
  • Volumetric: تعداد ردیف، اندازه Payload و Hot/Cold key؛
  • Historical: Event order، Audit trail و Versionهای قدیمی؛
  • Locale: فارسی/عربی، نیم‌فاصله، RTL، تقویم، منطقه زمانی و ریال/تومان.

برای هر بُعد سطح «ضروری، مفید، نامرتبط» بدهید. نام واقعی معمولاً نامرتبط است؛ Distribution مبلغ برای Performance یا Fraud ممکن است ضروری باشد.

گام ۳: داده و محیط را Classify کنید

فیلدها را Public، Internal، Confidential یا Restricted طبقه‌بندی کنید و Secret، Credential، Token، داده مالی، شناسه دولتی، سلامت، مکان، متن آزاد و Quasi-Identifier را جدا ببینید. محیط Non-production را ذاتاً امن‌تر فرض نکنید. کنترل‌های آمادگی محیط تست باید پیش از Provisioning برقرار باشند.

گام ۴: کم‌ریسک‌ترین Strategy کافی را انتخاب کنید

نیاز انتخاب پیش‌فرض چه زمانی گزینه دیگر لازم می‌شود؟
Unit/Component Fixture کوچک و Synthetic قطعی تقریباً هیچ‌گاه Production Record لازم نیست
API/Integration Factory + Seed + Sandbox Dependency برای Contract تاریخی، Snapshot بی‌حساسیت و نسخه‌دار
Regression در CI Scenario Dataset ثابت + تولید On-demand Dataset مشتق فقط با Gate حریم خصوصی
Exploratory ترکیب Scenarioهای Curated و Generator Patternهای تجمیعی Production برای کشف Bias مدل
UAT شخصیت و Workflow مصنوعی اما دامنه‌واقعی Subset کنترل‌شده برای Migration/History اثبات‌شده
Migration Synthetic برای Dry Runهای روزانه Subset De-identified/Masked در Rehearsal محدود
Performance Synthetic حجیم، کالیبره با Aggregate Metrics Replay رکورد/Traffic فقط پس از Transformation و Approval
Security Token و Account تست با داده غیرواقعی Production Secret یا Credential هرگز Test Data نیست
Analytics/ML Rule-based یا Privacy-evaluated Synthetic داده مرجع کنترل‌شده برای سنجش Utility/Bias
Incident reproduction بازسازی Synthetic از ویژگی‌های Failure کوچک‌ترین Slice ممکن در Enclave با Expiry

گام ۵: Decision Gate ثبت کنید

اگر داده از Production مشتق می‌شود، پاسخ «بله/خیر» این پرسش‌ها را ثبت کنید:

  • آیا همان Objective با Synthetic یا Aggregate قابل اثبات نیست؟
  • Purpose و Legal/Contract Basis توسط Owner مربوط تأیید شده است؟
  • کمینه‌سازی Column، Row، Date Range و گیرنده انجام شده است؟
  • Residual identifiers در متن آزاد، JSON، فایل، Log، Backup و Attachment جست‌وجو شده‌اند؟
  • Re-identification/Linkability متناسب با Context و گیرنده ارزیابی شده است؟
  • Access، Encryption، Audit، Retention، Deletion و Incident Owner روشن‌اند؟
  • Side Effectهای Email، SMS، پرداخت و Notification مسدود یا به Sandbox Route شده‌اند؟

یک «خیر» حل‌نشده یعنی Dataset هنوز Ready نیست، حتی اگر Pipeline با موفقیت آن را ساخته باشد.

اگر داده Production لازم شد، Masking را چگونه طراحی کنیم؟

روش را بر اساس رفتار موردنیاز انتخاب کنید

روش نمونه چه چیزی حفظ می‌شود؟ دام رایج
Redaction/Nulling حذف متن یادداشت نبودن مقدار تست Length/Parser دیگر واقعی نیست
Substitution نام از Dictionary تست نوع و طول تقریبی Collision یا نام واقعی ناخواسته
Format-preserving transform Token با همان Pattern Regex/Length فرمت معتبر ممکن است Side Effect واقعی بسازد
Consistent tokenization یک Customer همیشه یک Token Join و رابطه طولی Vault/Mapping هدف حمله است
Generalization سن به بازه سنی تحلیل گروهی Boundary دقیق از دست می‌رود
Shuffle جابجایی مقدار بین ردیف‌ها توزیع تک‌ستونه Correlation چندستونه شکسته یا هویت قابل استنتاج می‌ماند
Noise/Aggregation آمار بازه‌ای Trend تقریبی برای Assertion رکوردی مناسب نیست

Invariantهای فنی را فراموش نکنید

Transformation باید Referential Integrity، Unique constraint، Nullable، Checksum لازم، طول/Encoding، Tenant boundary و رابطه‌های دامنه را طبق Objective حفظ کند. همان مقدار حساس در DB، Cache، Search Index، Object Storage و Event Store باید با Policy سازگار تبدیل شود؛ وگرنه هم Leakage دارید و هم Test غیرقابل‌اعتماد.

بیشترین نشت همیشه در ستون name نیست

Ticket پشتیبانی، توضیح سفارش، فایل بارگذاری‌شده، Trace، Screenshot، Log و JSON آزاد می‌توانند شماره، Token و نشانی داشته باشند. OWASP Logging Cheat Sheet توصیه می‌کند Token، Password، داده شخصی حساس، داده بانکی و Secret مستقیم Log نشوند و در صورت نیاز حذف، Mask، Hash یا Encrypt شوند.

خروجی Masking را مثل یک محصول تست کنید

  • Scanner برای Direct Identifier، Secret pattern و دامنه‌های واقعی؛
  • Queryهای Constraint و Referential Integrity؛
  • نمونه‌گیری Quasi-Identifier و Linkability؛
  • مقایسه Distribution فقط در ابعاد موردنیاز؛
  • Negative test برای Mapping Vault و دسترسی غیرمجاز؛
  • Canary رکورد حساس ساختگی برای اثبات اینکه Pipeline آن را Transform می‌کند؛
  • تأیید Delete شدن Source snapshot، staging table و Artifactهای موقت.

داده Synthetic قابل‌اعتماد چگونه ساخته می‌شود؟

Scenario-first، نه Field-first

ابتدا Scenario و Expected Outcome را تعریف کنید، سپس Entityها را بسازید. برای Checkout ایرانی، «سفارش موفق»، «موجودی صفر»، «کوپن منقضی»، «آدرس لازم برای کالای فیزیکی» و «پرداخت Sandbox ردشده» بهتر از هزار ردیف نام‌گذاری‌نشده‌اند. هر Dataset باید بگوید نماینده کدام Partition، Boundary، State یا Rule است.

شناسه‌ای بسازید که به انسان واقعی برخورد نکند

برای Email و Domain از نام‌های رزروشده مثل example.test استفاده کنید؛ RFC 2606 دامنه‌های .test و .example را برای تست/مستندات رزرو کرده است. شماره موبایل، کارت، شبا، کد ملی یا نشانی ظاهراً معتبر را تصادفی نسازید: ممکن است متعلق به فرد واقعی باشد یا Side Effect بیرونی ایجاد کند. از Test Token و Sandbox رسمی ارائه‌دهنده استفاده و Egress را Deny-by-default کنید.

Seed بدون نسخه کافی نیست

Seed برای بازتولید لازم است، اما Generator، Locale، Dictionary و Dependency نیز باید Pin شوند. مستندات Faker تصریح می‌کند یک Seed با Method و Version یکسان خروجی یکسان می‌دهد، اما Dataset آن بین Patch versionها تضمین ثابت‌بودن ندارد. پس در Run Manifest نسخه Package را کنار Seed ذخیره کنید.

Realism را با معیار بسنجید

برای تست کارکردی، Rule/Scenario Coverage مهم‌تر از تقلید کل Distribution است. برای Performance یا Analytics، Frequency، Quantile، Null rate، Cardinality، Correlation و Hot keyهای لازم را با آمار تجمیعی و کمینه‌شده کالیبره کنید. «شبیه به چشم» معیار پذیرش نیست.

قالب Data Contract برای هر Dataset

فیلد نمونه/پرسش
dataset_id / version checkout-regression@3.2
objective / scope کدام Assertionها را پشتیبانی می‌کند و برای چه چیزی مناسب نیست؟
owner / approver QA Data Owner، Domain Owner و در صورت نیاز Privacy/Legal
source / classification Rule-based، Aggregate-derived، Masked subset؛ سطح حساسیت هر Field
schema / migration Schema version و Migration سازگار
generator identity Git SHA، Package lock، Seed، Locale و Config hash
scenario manifest Scenario ID، Partition/Boundary/Rule، Expected outcome
volume / fidelity Row count، Quantile/Distribution/Correlation لازم و Tolerance
privacy evidence Scanner، Linkability/Re-identification assessment و Reviewer
access / storage Role، Environment، Encryption، Audit و محل Artifact
side-effect policy Email/SMS/Payment/Webhook به Stub یا Sandbox
lifecycle Created at، Expiry، Reset، Retention و Delete evidence

مثال اجرایی: Dataset سفارش برای فروشگاه ایرانی

در مثال زیر هیچ PII واقعی و هیچ Package خارجی وجود ندارد. Generator با Seed و Run ID ثابت، Customer و Order مرتبط می‌سازد؛ Email فقط روی example.test است؛ و Scenarioهای موجودی صفر و کوپن منقضی عمداً در Manifest حضور دارند. این کد برای آموزش Data Contract است، نه Generator کامل ملی/بانکی.

import test from "node:test";
import assert from "node:assert/strict";

function mulberry32(seed) {
  return function random() {
    let value = (seed += 0x6d2b79f5);
    value = Math.imul(value ^ (value >>> 15), value | 1);
    value ^= value + Math.imul(value ^ (value >>> 7), value | 61);
    return ((value ^ (value >>> 14)) >>> 0) / 4294967296;
  };
}

function buildCheckoutDataset({ seed, runId }) {
  const random = mulberry32(seed);
  const scenarios = ["happy_path", "out_of_stock", "expired_coupon"];
  const customers = scenarios.map((_, index) => ({
    id: `${runId}-customer-${index + 1}`,
    email: `qa-${runId}-${index + 1}@example.test`,
    locale: index === 0 ? "fa-IR" : "en-US"
  }));

  const orders = scenarios.map((scenario, index) => {
    const quantity = 1 + Math.floor(random() * 3);
    const unitPriceRial = (10 + Math.floor(random() * 90)) * 100_000;
    return {
      id: `${runId}-order-${index + 1}`,
      customerId: customers[index].id,
      scenario,
      quantity,
      unitPriceRial,
      totalRial: quantity * unitPriceRial,
      stock: scenario === "out_of_stock" ? 0 : 10,
      couponExpiresAt: scenario === "expired_coupon"
        ? "2025-01-01T00:00:00Z"
        : "2030-01-01T00:00:00Z",
      expected: scenario === "happy_path" ? "accepted" : "rejected"
    };
  });

  return {
    manifest: {
      datasetId: "checkout-regression@1.0",
      generator: "builtin-demo@1",
      seed,
      runId,
      scenarios
    },
    customers,
    orders
  };
}

test("same seed and run id are reproducible", () => {
  const input = { seed: 1405, runId: "ci-42" };
  assert.deepEqual(buildCheckoutDataset(input), buildCheckoutDataset(input));
});

test("parallel runs have isolated identifiers", () => {
  const first = buildCheckoutDataset({ seed: 1405, runId: "ci-42" });
  const second = buildCheckoutDataset({ seed: 1405, runId: "ci-43" });
  assert.notEqual(first.orders[0].id, second.orders[0].id);
});

test("referential and monetary invariants hold", () => {
  const data = buildCheckoutDataset({ seed: 1405, runId: "ci-42" });
  const customerIds = new Set(data.customers.map(customer => customer.id));
  for (const order of data.orders) {
    assert.ok(customerIds.has(order.customerId));
    assert.equal(order.totalRial, order.quantity * order.unitPriceRial);
  }
});

test("all email destinations use a reserved test domain", () => {
  const data = buildCheckoutDataset({ seed: 1405, runId: "ci-42" });
  assert.ok(data.customers.every(customer => customer.email.endsWith("@example.test")));
});

test("required rare scenarios and oracles exist", () => {
  const data = buildCheckoutDataset({ seed: 1405, runId: "ci-42" });
  const byScenario = Object.fromEntries(data.orders.map(order => [order.scenario, order]));
  assert.equal(byScenario.out_of_stock.stock, 0);
  assert.equal(byScenario.out_of_stock.expected, "rejected");
  assert.equal(byScenario.expired_coupon.expected, "rejected");
  assert.equal(byScenario.happy_path.expected, "accepted");
});

چه چیزهایی را برای بازار ایران جدا مدل کنیم؟

  • حروف فارسی/عربی مثل ی/ی و ک/ک، نیم‌فاصله، Emoji و متن RTL/LTR ترکیبی؛
  • رقم فارسی، عربی و لاتین و Policy صریح Normalize/Reject؛
  • ریال در Storage و تومان در UI با Round/Display Oracle روشن؛
  • تقویم جلالی در نمایش در برابر Timestamp استاندارد در Contract؛
  • Zone و Offset زمان، مرز روز/ماه، تعطیلی و Cut-off تسویه؛
  • استان/شهر/کدپستی ساختگی اما سازگار با Ruleهای ارسال؛
  • PSP، پیامک، ایمیل و نقشه فقط در Sandbox/Stub و با Egress control؛
  • Dependencyهای داخلی/خارجی، قطعی شبکه و محدودیت دسترسی به Registry یا سرویس ابری.

اگر Validator واقعاً فرمت شماره یا شناسه را می‌سنجد، تیم باید Range/Token تست مصوب داشته باشد؛ تولید رشته‌ای که فقط «واقعی به نظر می‌رسد» راه امنی نیست.

چگونه کیفیت داده تست را اندازه بگیریم؟

یک امتیاز کلی «Data Quality = ۹۵٪» مبهم است. معیار را به Objective و Failure قابل‌تشخیص وصل کنید.

بُعد معیار نمونه Gate نمونه
Schema درصد رکوردهای پذیرفته‌شده توسط Schema version هدف ۱۰۰٪ برای داده Valid؛ ۱۰۰٪ Reject برای Fixtureهای Invalid
Relationship Orphan، Duplicate و Constraint violation ناخواسته صفر مورد ناخواسته
Scenario Scenario/Partition/Boundary پوشش‌داده‌شده ÷ مدل نسخه‌دار طبق Risk و Test Plan
Statistical Quantile، Null rate، Cardinality و Correlation منتخب Tolerance از پیش تعریف‌شده
Privacy Direct identifier/Secret hit، Linkability و Attack-based assessment Threshold مصوب Owner؛ Hit بحرانی صفر
Reproducibility بازسازی همان Hash با Generator/Seed/Config یکسان Hash یکسان
Freshness سن Schema/Rule/Aggregate مرجع کمتر از SLA تعریف‌شده
Operational Provision time، reset success، collision بین Workerها طبق SLO Pipeline

شباهت آماری بیشتر همیشه بهتر نیست؛ ممکن است Privacy را کاهش دهد. برعکس، Noise بیشتر می‌تواند Dataset را برای هدف تست بی‌فایده کند. این Trade-off باید برای همان Use Case و گیرنده سنجیده شود، نه با یک Threshold جهانی.

چرخه عملی Provision تا Delete

  1. Discover: Test Objective، Test Basis و Data dependency را فهرست کنید.
  2. Design: کمترین Fidelity و Scenarioهای لازم را مشخص کنید.
  3. Classify: Source، Fieldها، محیط و گیرنده را طبقه‌بندی کنید.
  4. Approve: برای داده مشتق از Production، Owner و Basis را ثبت کنید.
  5. Build: Generator/Transformation را کد، Review و Version کنید.
  6. Validate: Schema، Rule، Distribution، Privacy و Side Effect را Gate کنید.
  7. Package: Dataset ID، Hash، Manifest و Expiry را در Registry داخلی ثبت کنید.
  8. Provision: برای هر Run/Worker Namespace و Credential کم‌اختیار بسازید.
  9. Observe: Result و ID سناریو را ثبت کنید، نه Payload حساس را.
  10. Reset/Delete: داده، Snapshot، Log و Artifact موقت را طبق Policy حذف و Evidence نگه دارید.

برای محیط‌های Container-based، الگوی Health→Migration→Seed→Test→Evidence→Teardown در راهنمای Docker Compose برای محیط تست توضیح داده شده است. Dataset باید پس از Migration و پیش از Readiness Test تزریق شود، نه اینکه DB نامشخصی از Run قبلی به ارث برسد.

الگوی امن داده تست در CI/CD

  • Fixture کوچک و کاملاً Synthetic را می‌توان پس از Review در Repository نگه داشت؛ Snapshot مشتق از Production را نه.
  • Generator، Lockfile، Seed، Locale، Schema version و Config hash بخشی از Build identity باشند.
  • هر Pipeline/Worker، Tenant/Schema/Prefix مستقل بگیرد تا Parallel runها Collision نسازند.
  • Secret، Mapping Vault و Production credential از Repository و Test Artifact جدا بمانند.
  • Email/SMS/Webhook/Payment/Push به Stub یا Sandbox Route و Egress غیرمجاز مسدود شود.
  • JUnit/Report فقط Dataset ID و Scenario ID را ثبت کند؛ Payload کامل در Log یا Screenshot نریزد.
  • Retry داده را بی‌صدا عوض نکند. اگر Regenerate می‌شود، Seed و Dataset version جدید در Evidence بیاید.
  • Cleanup در مسیر Pass، Fail، Timeout و Cancel اجرا شود و Failure آن دیده شود.

راهنمای Jenkins و GitLab CI/CD قرارداد Artifact، Cache، Evidence و Cleanup را کامل‌تر پوشش می‌دهد. Dataset یک Artifact نسخه‌دار است؛ Cache بی‌هویت یا State مشترک نیست.

داده تست برای Performance چه تفاوتی دارد؟

ساختن ده میلیون Row به‌تنهایی Realism ایجاد نمی‌کند. Query plan و Cache hit به Key distribution، Selectivity، Index، Row width، Relation cardinality، History و Hotspot وابسته‌اند. Workload نیز باید Read/Write mix و Arrival model درست داشته باشد. در راهنمای تست Performance طراحی Workload و SLO جدا توضیح داده شده است.

رویکرد پیشنهادی:

  1. از Production فقط Aggregate/Histogram حداقلی و مجاز بگیرید؛
  2. داده Synthetic را با Quantile و Cardinalityهای ضروری کالیبره کنید؛
  3. PII، Payload واقعی و Secret را وارد Generator نکنید؛
  4. Generator و Load Generator را جدا Benchmark کنید تا Setup گلوگاه تست نشود؛
  5. پس از Seed، DB stats/Index readiness را کنترل و سپس Load را شروع کنید؛
  6. Hash و Summary Dataset را کنار نتیجه Performance نگه دارید.

بازتولید باگ بدون کپی کامل رکورد مشتری

  1. از Bug Evidence فقط ویژگی رفتاری لازم را استخراج کنید: Length، Encoding، State، Relation یا Sequence.
  2. آن ویژگی را به Fixture Synthetic حداقلی تبدیل کنید.
  3. تست Regression ابتدا روی نسخه معیوب Fail و روی Fix Pass شود.
  4. اگر بازتولید نشد، Slice را مرحله‌ای و با Approval گسترش دهید.
  5. هر داده مشتق‌شده Expiry و Delete evidence داشته باشد.

این روش هم Debugging را تکرارپذیر می‌کند و هم دامنه افشا را کاهش می‌دهد. Screenshot یا Export کامل Production نباید Shortcut عادی گزارش باگ باشد.

Anti-patternهای رایج

  • Restore کردن Backup تولید در Staging با این فرض که «شبکه داخلی است»؛
  • Hash کردن فقط نام/ایمیل و نادیده‌گرفتن Quasi-Identifier، متن آزاد و Attachment؛
  • نامیدن Masking به‌عنوان Anonymization بدون Threat model یا سنجش بازشناسایی؛
  • Random مستقل برای هر Column و شکستن Ruleها و Foreign keyها؛
  • Seed ثابت بدون Pin کردن نسخه Generator/Dictionary/Locale؛
  • ساخت شماره/ایمیل/کارت ظاهراً واقعی و فعال ماندن Side Effect؛
  • اشتراک DB و Account بین تست‌های موازی؛
  • چاپ Payload در Log، Report، Screenshot یا Prompt ابزارهای بیرونی؛
  • استفاده از Synthetic آماری بدون Privacy attack و Utility test؛
  • نگهداری Dataset «موقت» بدون Owner، Expiry و Delete evidence.

Scorecard ساده برای تصمیم تیم

به هر گزینه از ۱ تا ۵ امتیاز دهید؛ Weight را بر اساس Objective تعیین کنید. Privacy یک Must-have است و نباید با امتیاز سرعت Provisioning جبران شود.

معیار سؤال ماهیت
Privacy/Compliance Residual risk و Basis قابل‌قبول است؟ Must-have
Scenario coverage Rare/Invalid/Boundary/State لازم را می‌سازد؟ وزن‌دار
Structural/relational fidelity Schema و Invariantهای موردنیاز را حفظ می‌کند؟ Must-have برای همان تست
Statistical fidelity فقط Distributionهای لازم در Tolerance هستند؟ وابسته به Use Case
Reproducibility Run با Manifest قابل بازسازی است؟ Must-have برای CI
Provision/reset time SLO Pipeline را رعایت می‌کند؟ وزن‌دار
Maintenance با Schema/Rule change چه هزینه‌ای دارد؟ وزن‌دار
Auditability Source، Approval، Access و Delete evidence روشن‌اند؟ Must-have برای داده مشتق

برنامه ۱۴ روزه برای اصلاح Data Strategy

روز ۱ تا ۳: Inventory و Stop-the-bleeding

  • Dataset، Snapshot، Export و Logهای محیط تست را فهرست و Owner تعیین کنید.
  • Production credential و Side Effect مستقیم را مسدود کنید.
  • Datasetهای بدون Basis/Expiry را Quarantine کنید، نه اینکه بدون بررسی پاک یا منتشر شوند.

روز ۴ تا ۷: Contract و Pilot

  • یک Journey پرریسک مثل Checkout را انتخاب کنید.
  • Data Contract، Scenario Manifest و Generator نسخه‌دار بسازید.
  • Schema/Relationship/Scenario/Privacy Gate را به Pipeline اضافه کنید.

روز ۸ تا ۱۱: Isolation و Lifecycle

  • Namespace مستقل برای هر Run/Worker ایجاد کنید.
  • Provision/reset/teardown و Expiry را خودکار کنید.
  • Report را از Payload به Dataset ID و Scenario ID تغییر دهید.

روز ۱۲ تا ۱۴: Evidence و Portfolio

  • Privacy/Utility trade-off و زمان Pipeline را Baseline کنید.
  • موارد استثنایی نیازمند Masked subset را با Approval تعریف کنید.
  • Pattern موفق را به Journeyهای بعدی گسترش دهید.

چک‌لیست نهایی داده تست

  • Test Objective و Fidelity لازم مکتوب است.
  • نوع داده با واژه دقیق Production/Masked/Pseudonymized/Anonymized/Synthetic ثبت شده است.
  • کم‌ریسک‌ترین Strategy کافی انتخاب شده است.
  • داده Production فقط با Basis، Owner و Scope حداقلی وارد می‌شود.
  • Schema، Relation، Rule، Scenario و Distribution لازم Gate دارند.
  • Privacy با Scanner صرف پایان نمی‌یابد و Linkability/Attack متناسب سنجیده می‌شود.
  • Generator، Dependency، Seed، Locale و Config نسخه‌دارند.
  • Email/SMS/Payment/Webhook بیرونی مسدود یا Sandbox است.
  • هر Run Namespace مستقل دارد.
  • Log و Report شامل Secret یا Payload حساس نیست.
  • Retention، Expiry، Reset، Delete و Audit evidence تعریف شده است.
  • با تغییر Schema، Rule یا Threat model، Dataset دوباره Validate می‌شود.

جمع‌بندی

انتخاب بین داده تست واقعی و مصنوعی یک رأی همیشگی نیست. داده Production الگوهای تاریخی ارزشمندی دارد، اما Coverage کامل و امنیت ذاتی نمی‌دهد. داده Synthetic کنترل، تکرارپذیری و ساخت سناریوی نادر را آسان می‌کند، اما ممکن است Fidelity ضعیف یا—اگر از مدل آموزش‌دیده بر داده شخصی آمده باشد—Privacy risk داشته باشد.

راه سالم یک Portfolio هدف‌محور است: Objective → Minimum Fidelity → Classification → Strategy → Contract → Privacy/Utility Gate → Isolated Provision → Evidence → Expiry. برای بیشتر CIها از Synthetic قطعی شروع کنید؛ فقط وقتی Evidence نشان می‌دهد کافی نیست، کمترین داده مشتق از Production را با کنترل و زمان انقضای روشن اضافه کنید.

سوالات متداول

برای تست نرم‌افزار داده واقعی بهتر است یا مصنوعی؟

برای بیشتر Unit، Integration و Regression، Synthetic قطعی و Scenario-based بهتر کنترل می‌شود. برای Migration، تحلیل الگوی تاریخی یا بازتولید Failure خاص ممکن است Subset مشتق از Production لازم باشد. انتخاب باید بر Test Objective، Fidelity و Privacy risk استوار باشد.

آیا داده Masked همان داده ناشناس است؟

خیر. Masking یک یا چند مقدار را تغییر می‌دهد، اما Quasi-Identifier، Mapping، متن آزاد یا داده کمکی ممکن است اتصال به فرد را ممکن نگه دارد. Anonymization به ارزیابی Context و ریسک شناسایی نیاز دارد.

آیا داده Synthetic همیشه فاقد اطلاعات شخصی است؟

Rule-based Synthetic که بدون رکورد واقعی ساخته می‌شود معمولاً ریسک بسیار کمتری دارد. اما Model-based Synthetic ممکن است اطلاعات داده آموزشی را Memorize یا قابل استنتاج کند؛ بنابراین Privacy و Utility آن باید سنجیده شود.

برای تست Performance باید دیتابیس Production را کپی کنیم؟

معمولاً نه. داده حجیم Synthetic را با Aggregateهای مجاز مثل Cardinality، Quantile، Null rate و Hot-key distribution کالیبره کنید. کپی Production فقط در Scope استثنایی، کنترل‌شده و مصوب قابل بررسی است.

برای تکرارپذیری فقط ذخیره Seed کافی است؟

خیر. نسخه Generator و Package، Dictionary، Locale، Schema، Config و Run namespace نیز روی خروجی اثر دارند. Manifest کامل و Hash Dataset را کنار نتیجه تست نگه دارید.

منابع رسمی و قابل بازبینی

دیدگاهتان را بنویسید