استراتيجية الاختبار — نظام إدارة المغسلة
معلومات الوثيقة
| الحقل |
القيمة |
| المشروع |
نظام إدارة المغسلة |
| الإصدار |
1.0 |
| اللغة |
العربية |
| نوع الوثيقة |
استراتيجية الاختبار وضمان الجودة |
1. هرم الاختبارات
| الطبقة |
النسبة |
الأداة |
التغطية المستهدفة |
| وحدة |
70% |
xUnit (خلفية)، Jest (واجهة) |
≥ 80% إجمالي |
| تكامل |
20% |
TestContainers (خلفية)، TestBed (واجهة) |
100% للمسارات الحرجة |
| يدوي / E2E |
10% |
قائمة تدقيق Tauri يدوية |
جميع الميزات لكل إصدار |
2. اختبارات الخلفية (xUnit + TestContainers)
اختبارات الوحدة
[Fact]
public void Evaluate_InvoiceCreated_PaidByCash_ReturnsCorrectEntries()
{
var engine = new AccountingRulesEngine(GetTestRules());
var invoice = CreateTestInvoice(grandTotal: 150.00m);
var entries = engine.Evaluate("InvoiceCreated", invoice, PaymentMethod.Cash);
entries.Should().HaveCount(2);
entries[0].AccountCode.Should().Be("1000"); // نقدية
entries[0].Debit.Should().Be(150.00m);
entries[1].AccountCode.Should().Be("4000"); // إيراد غسيل
entries[1].Credit.Should().Be(150.00m);
}
اختبارات تكاملية مع TestContainers
public class InvoiceIntegrationTests : IAsyncLifetime
{
private readonly PostgreSqlContainer _postgres =
new PostgreSqlBuilder().WithDatabase("laundry_test").Build();
[Fact]
public async Task CreateInvoice_WithPayment_SavesInvoiceAndPostsToGL()
{
var result = await CreateHandler().Handle(new CreateInvoiceCommand(...), ct);
result.IsSuccess.Should().BeTrue();
var glLines = await GetGlLinesForInvoice(result.Value.Id);
glLines.Sum(x => x.Debit).Should().Be(glLines.Sum(x => x.Credit));
}
}
سيناريوهات الاختبار الأساسية
- المصادقة: دخول ناجح، كلمة مرور خاطئة، رمز منتهٍ، دور مفقود
- الفاتورة: مسودة، تأكيد، تغيير حالة، إلغاء، منع تكرار الرقم
- الدفع: فردي، متعدد الطرق، جزئي، رفض دفع زائد
- المحاسبة: جميع التدفقات الـ 13 تولد قيوداً صحيحة
- السجاد: إيصال ← فاتورة نهائية، خصم عربون، فائض رصيد
- الخياطة: تعيين خياط، تسجيل تكلفة، حساب المستحقات
- الترخيص: ساري، سماح، إيقاف تام، ملف تالف
- المزامنة: تصدير، استيراد، تكرار الاستيراد
3. اختبارات الواجهة (Jest + TestBed)
اختبار مكون
describe('InvoiceListContainer', () => {
it('يجب عرض الفواتير من المتجر', () => {
store.overrideSelector(selectAllInvoices, [{ id: '1', invoiceNumber: 'INV-001' }]);
store.refreshState();
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('INV-001');
});
});
اختبار خدمة
it('يجب استدعاء GET /api/invoices', () => {
service.getAll().subscribe(invoices => expect(invoices.length).toBe(2));
const req = httpMock.expectOne('/api/invoices');
req.flush([{ id: '1' }, { id: '2' }]);
});
اختبار NgRx Effects
it('يجب إرجاع loadSuccess عند النجاح', (done) => {
service.getAll.mockReturnValue(of([{ id: '1' }]));
actions$ = of(InvoiceActions.load());
effects.load$.subscribe(result => {
expect(result).toEqual(InvoiceActions.loadSuccess({ invoices: [{ id: '1' }] }));
done();
});
});
4. اختبار تكامل Tauri
import { mockIPC } from '@tauri-apps/api/mocks';
mockIPC((cmd) => {
switch (cmd) {
case 'compute_client_token': return 'test-token-abc123';
case 'start_docker_services': return 'OK';
}
});
it('يجب حساب رمز العميل', async () => {
const token = await service.computeClientToken();
expect(token).toBe('test-token-abc123');
});
5. اختبارات التحقق المحاسبي
كل تدفق محاسبي يجب أن يجتاز اختبار القاعدة الذهبية:
[Theory]
[ClassData(typeof(AccountingScenarioProvider))]
public void AccountingFlow_Always_Balances(string scenario, Func<Task<Guid>> act)
{
var referenceId = await act();
var glLines = await GetGlLinesForReference(referenceId);
var totalDebit = glLines.Sum(x => x.Debit);
var totalCredit = glLines.Sum(x => x.Credit);
totalDebit.Should().Be(totalCredit,
$"السيناريو '{scenario}' أنتج قيوداً غير متوازنة");
}
تشمل السيناريوهات الـ 17: فاتورة نقدية، آجلة، جزئية، مع مخزون، عربون سجاد، فاتورة نهائية بفائض/نقص، نماذج تسوية الشركات الثلاثة، نماذج دفع الخياطين الثلاثة، تعويض نقدي/دائن، استرداد، إلغاء.
6. اختبارات المزامنة
[Fact]
public async Task ExportImport_RoundTrip_ProducesIdenticalData()
{
// إنشاء بيانات ← تصدير ← استيراد ← تعداد الصفوف متطابق
var result = await importService.ImportAsync(syncFile);
centralCount.Should().Be(offlineCount);
}
[Fact]
public async Task Reimport_SameFile_Twice_IsIdempotent()
{
await importService.ImportAsync(syncFile);
var result = await importService.ImportAsync(syncFile);
result.RowsImported.Should().Be(0); // لم يستورد شيئاً
}
7. متطلبات تغطية الكود
| الطبقة |
الأداة |
الحد الأدنى |
المستهدف |
| وحدة الخلفية |
coverlet |
80% |
90% |
| تكامل الخلفية |
coverlet |
100% للتدفقات المحاسبية |
|
| وحدة الواجهة |
Jest |
70% |
85% |
8. تنفيذ الاختبار في CI
- run: dotnet test --no-build -c Release --collect:"XPlat Code Coverage"
- run: npm test -- --watch=false --coverage --ci
- name: التحقق من حدود التغطية
run: reportgenerator -reports:**/coverage.cobertura.xml
9. قائمة التدقيق اليدوي — Tauri
تنفذ قبل كل GitHub Release على المنصات الثلاث:
التثبيت
- [ ] تثبيت من
.msi / .dmg / .deb
- [ ] أول تشغيل يظهر المعالج
- [ ] إنشاء مسؤول بكلمة مرور تلقائية ومخصصة
الأساسيات
- [ ] إنشاء فاتورة: إضافة بنود، اختيار قطعة وخدمة، تأكيد
- [ ] مسودة ← مؤكدة ← جاهزة ← مسلّمة
- [ ] بطاقات باركود تولد وتطبع
- [ ] دفع: نقدي، بطاقة، متعدد، جزئي
- [ ] بحث عن الفواتير
- [ ] وردية: فتح ← مبيعات ← إغلاق ← فروقات
السجاد والخياطة
- [ ] إيصال سجاد ← فاتورة نهائية
- [ ] 3 استراتيجيات تسعير
- [ ] طلب خياطة مع تعيين خياط
- [ ] تقرير مستحقات
سطح المكتب
- [ ] فتح المتصفح يعرض 403 (الفرع غير المتصل)
- [ ] انتهاء الترخيص: شريط أحمر (أيام 1-7)
- [ ] إيقاف تام: الكتابة ممنوعة (يوم 8+)
- [ ] استبدال license.dat: يستعيد التطبيق
الطباعة والتصدير
- [ ] طباعة حرارية على ورق 80mm
- [ ] طباعة A4
- [ ] تصدير Excel و PDF
سجل المراجعة
| التاريخ |
الإصدار |
المعد |
التغييرات |
| 2026-05-10 |
1.0 |
قائد الجودة |
الإصدار الأولي لاستراتيجية الاختبار |