رفتن به محتوای اصلی

داده تست واقعی یا مصنوعی؟ مقایسه، امنیت و انتخاب

داده تست واقعی، Masked و Synthetic را از نظر امنیت، واقع‌گرایی و تکرارپذیری مقایسه کنید؛ با ماتریس انتخاب، کنترل حریم خصوصی و مثال اجرایی.

محمد عسکری ۲۰ دقیقه مطالعه به‌روزرسانی
فهرست مطالب
  1. این مقاله چه مسئله‌ای را حل می‌کند؟
  2. اول واژه‌ها را از هم جدا کنیم
  3. Production-like با Production یکسان نیست
  4. Synthetic با Random مترادف نیست
  5. پنج باور خطرناک درباره داده واقعی و مصنوعی
  6. ۱. «ریسک داده مصنوعی صفر است»
  7. ۲. «Synthetic یا Masked یعنی انطباق خودکار»
  8. ۳. «داده واقعی به‌طور طبیعی پوشش کامل دارد»
  9. ۴. «UAT حتماً به داده واقعی نیاز دارد»
  10. ۵. «AI خودش داده امن و باکیفیت تولید می‌کند»
  11. چارچوب انتخاب: Objective → Fidelity → Risk → Strategy
  12. گام ۱: Test Objective را یک‌خطی کنید
  13. گام ۲: Fidelity لازم را بُعدبه‌بُعد تعیین کنید
  14. گام ۳: داده و محیط را Classify کنید
  15. گام ۴: کم‌ریسک‌ترین Strategy کافی را انتخاب کنید
  16. گام ۵: Decision Gate ثبت کنید
  17. اگر داده Production لازم شد، Masking را چگونه طراحی کنیم؟
  18. روش را بر اساس رفتار موردنیاز انتخاب کنید
  19. Invariantهای فنی را فراموش نکنید
  20. بیشترین نشت همیشه در ستون name نیست
  21. خروجی Masking را مثل یک محصول تست کنید
  22. داده Synthetic قابل‌اعتماد چگونه ساخته می‌شود؟
  23. Scenario-first، نه Field-first
  24. شناسه‌ای بسازید که به انسان واقعی برخورد نکند
  25. Seed بدون نسخه کافی نیست
  26. Realism را با معیار بسنجید
  27. قالب Data Contract برای هر Dataset
  28. مثال اجرایی: Dataset سفارش برای فروشگاه ایرانی
  29. چه چیزهایی را برای بازار ایران جدا مدل کنیم؟
  30. چگونه کیفیت داده تست را اندازه بگیریم؟
  31. چرخه عملی Provision تا Delete
  32. الگوی امن داده تست در CI/CD
  33. داده تست برای Performance چه تفاوتی دارد؟
  34. بازتولید باگ بدون کپی کامل رکورد مشتری
  35. Anti-patternهای رایج
  36. Scorecard ساده برای تصمیم تیم
  37. برنامه ۱۴ روزه برای اصلاح Data Strategy
  38. روز ۱ تا ۳: Inventory و Stop-the-bleeding
  39. روز ۴ تا ۷: Contract و Pilot
  40. روز ۸ تا ۱۱: Isolation و Lifecycle
  41. روز ۱۲ تا ۱۴: Evidence و Portfolio
  42. چک‌لیست نهایی داده تست
  43. جمع‌بندی
  44. سوالات متداول
  45. برای تست نرم‌افزار داده واقعی بهتر است یا مصنوعی؟
  46. آیا داده Masked همان داده ناشناس است؟
  47. آیا داده Synthetic همیشه فاقد اطلاعات شخصی است؟
  48. برای تست Performance باید دیتابیس Production را کپی کنیم؟
  49. برای تکرارپذیری فقط ذخیره Seed کافی است؟
  50. منابع رسمی و قابل بازبینی
داده تست واقعی یا مصنوعی؟ مقایسه، امنیت و انتخاب

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

یک کپی از دیتابیس 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/ComponentFixture کوچک و Synthetic قطعیتقریباً هیچ‌گاه Production Record لازم نیست
API/IntegrationFactory + Seed + Sandbox Dependencyبرای Contract تاریخی، Snapshot بی‌حساسیت و نسخه‌دار
Regression در CIScenario Dataset ثابت + تولید On-demandDataset مشتق فقط با Gate حریم خصوصی
Exploratoryترکیب Scenarioهای Curated و GeneratorPatternهای تجمیعی Production برای کشف Bias مدل
UATشخصیت و Workflow مصنوعی اما دامنه‌واقعیSubset کنترل‌شده برای Migration/History اثبات‌شده
MigrationSynthetic برای Dry Runهای روزانهSubset De-identified/Masked در Rehearsal محدود
PerformanceSynthetic حجیم، کالیبره با Aggregate MetricsReplay رکورد/Traffic فقط پس از Transformation و Approval
SecurityToken و Account تست با داده غیرواقعیProduction Secret یا Credential هرگز Test Data نیست
Analytics/MLRule-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 transformToken با همان PatternRegex/Lengthفرمت معتبر ممکن است Side Effect واقعی بسازد
Consistent tokenizationیک Customer همیشه یک TokenJoin و رابطه طولی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 / versioncheckout-regression@3.2
objective / scopeکدام Assertionها را پشتیبانی می‌کند و برای چه چیزی مناسب نیست؟
owner / approverQA Data Owner، Domain Owner و در صورت نیاز Privacy/Legal
source / classificationRule-based، Aggregate-derived، Masked subset؛ سطح حساسیت هر Field
schema / migrationSchema version و Migration سازگار
generator identityGit SHA، Package lock، Seed، Locale و Config hash
scenario manifestScenario ID، Partition/Boundary/Rule، Expected outcome
volume / fidelityRow count، Quantile/Distribution/Correlation لازم و Tolerance
privacy evidenceScanner، Linkability/Re-identification assessment و Reviewer
access / storageRole، Environment، Encryption، Audit و محل Artifact
side-effect policyEmail/SMS/Payment/Webhook به Stub یا Sandbox
lifecycleCreated 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
RelationshipOrphan، Duplicate و Constraint violation ناخواستهصفر مورد ناخواسته
ScenarioScenario/Partition/Boundary پوشش‌داده‌شده ÷ مدل نسخه‌دارطبق Risk و Test Plan
StatisticalQuantile، Null rate، Cardinality و Correlation منتخبTolerance از پیش تعریف‌شده
PrivacyDirect identifier/Secret hit، Linkability و Attack-based assessmentThreshold مصوب Owner؛ Hit بحرانی صفر
Reproducibilityبازسازی همان Hash با Generator/Seed/Config یکسانHash یکسان
Freshnessسن Schema/Rule/Aggregate مرجعکمتر از SLA تعریف‌شده
OperationalProvision 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/ComplianceResidual risk و Basis قابل‌قبول است؟Must-have
Scenario coverageRare/Invalid/Boundary/State لازم را می‌سازد؟وزن‌دار
Structural/relational fidelitySchema و Invariantهای موردنیاز را حفظ می‌کند؟Must-have برای همان تست
Statistical fidelityفقط Distributionهای لازم در Tolerance هستند؟وابسته به Use Case
ReproducibilityRun با Manifest قابل بازسازی است؟Must-have برای CI
Provision/reset timeSLO Pipeline را رعایت می‌کند؟وزن‌دار
Maintenanceبا Schema/Rule change چه هزینه‌ای دارد؟وزن‌دار
AuditabilitySource، 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 را کنار نتیجه تست نگه دارید.

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

این مقاله را با دیگران به اشتراک بگذارید

نویسنده

محمد عسکری

محمد هستم، توسعه‌دهنده وب با بیش از ده سال تجربه در برنامه‌نویسی سمت سرور و کاربر. به یادگیری و اشتراک‌گذاری دانش علاقه‌مندم و اخیراً تمرکزم را روی حوزه تست نرم‌افزار گذاشته‌ام تا تجربیاتم را در این زمینه نیز به اشتراک بگذارم و به درک بهتر کیفیت نرم‌افزار کمک کنم.

همه مقاله‌ها

ادامه مطالعه

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

ایستگاه بعدی شما

TestRail را همین حالا در محیط دمو ببینید.

محیط تست آماده

دسترسی به دمو TestRail

قبل از ورود، مشخصات زیر را در صفحه ورود محیط دمو وارد کنید.

آدرس دمو

https://demo.testrail.ir

ایمیل ورود

demo@testrail.ir

رمز عبور

demo_user