الزاوي: اختبار التكامل (اختبار سطحي)



عندما ينمو التطبيق ، أو من المهم جدًا بالنسبة لنا أن يعمل بشكل صحيح مع أي إعادة بناء ، نبدأ في التفكير في اختبار الوحدة أو e2e.

لعدة سنوات من العمل مع Angular - التطبيقات في قطاع الشركات ، بعد أن اكتشفت العديد من المشاكل عند إعادة الهيكلة وإنشاء وظائف جديدة ، لا تبدو الاختبارات مضيعة للوقت ، ولكنها مفتاح الاستقرار في أيدي المبرمجين.

بعد ذلك ، دعنا نحاول فهم كيفية اختبار التطبيق الأساسي على Angular ولمس القليل من النظرية.

لنبدأ بأنواع الاختبارات التي يمكن لمطوري التطبيقات القيام بها (في حالتنا ، الواجهة الأمامية).



(Martin Fowler و Google Testing Blog)

تمتلك Angular مثل هذه الأساليب خارج الصندوق.

دعونا نلقي نظرة فاحصة على هرم الاختبار باستخدام مثال التطبيقات الزاويّة.

اختبار الوحدة - الاختبار المعزول للطرق الصفية. نتحقق من تشغيل الطريقة ، ونمرر مجموعات مختلفة من المعلمات إلى المدخلات ، ونقارن النتيجة بالنتيجة المتوقعة.

على سبيل المثال ، لدينا مكون يتم فيه تحويل السلاسل السداسية إلى rgb ، ويتم عرض هذه المعلومات للمستخدم ، وإرسالها أيضًا إلى الخادم المتبقي.

إذا بدأنا في النظر نحو اختبارات الوحدة ، فيمكننا كتابة العديد من الاختبارات لكل طريقة في فئة المكونات.

إذا كان لدينا سلسلة rgbToHex (hex: string) => string ، ثم لاختبار طريقة بمثل هذا التوقيع ، نحتاج إلى القيام بما يلي: توقع (rgbToHex ('777')). ToBe ('rgb (119، 119، 119)') .

يبدو الأمر رائعًا ، ولكن لدينا مشكلة بسبب العدد الكبير من الوظائف التي يجب تغطيتها ، ونحن كسالى جدًا في كتابة الاختبارات. بالإضافة إلى ذلك ، حتى كتابة اختبارات الوحدة لكل طريقة في المكون ، فإننا لا نضمن صحة عملهم المشترك.

على سبيل المثال ، بعد إنشاء واختبار مكون إخراج الجدول ، يمكننا تسميته في مكون "الآلة الحاسبة" ، ولكن تحديد الخطأ في الربط الخاطئ. ثم لن تقع البيانات في الجداول ، ولن تعمل مكونات العمل بشكل صحيح بشكل صحيح.

صورة

اختبار التكامل- اختبار مجموعة من المكونات. من هذه المرحلة ، نبدأ باختبار ليس فقط طرق الفصل ، ولكن أيضًا ارتباطها بـ html ، أي انقر على العناصر داخل المكون. غالبًا ما يتم العثور على الاختبار الضحل في التدوين الزاوي ، وهو في الأساس اختبار التكامل.

في اختبار Shallow ، سنستعرض المزيد من التفاصيل أدناه. اختبار

E2E (من طرف إلى طرف) - طريقة لاختبار التطبيق بالكامل لحل مشاكل اختبارات الوحدة.

باستخدام هذا النهج ، نكتب نصوصًا تجريبية للاختبار لتقديمها بشكل كامل ، أي يتم تجميع جميع المكونات والخدمات معًا ، ونعيد إنتاج إجراءات المستخدم.
هذا رائع جدًا ، ولكن قد تكون لدينا مشكلة في تغيير بذرة ديناميكيًا (عادةً خادم json ثابت على node.js) ، ولعب مواقف مختلفة ، قد نحتاج إلى بيانات مختلفة من الخادم الذي تمت مضاهاته.

على سبيل المثال: لدينا صفحة تحتوي على قائمة المستخدمين ، أحد عناصر هذه اللوحة هو ترقيم الصفحات. يجب أن تتصرف بشكل مختلف مع أعداد مختلفة من المستخدمين. ولكن إذا تم تعيين البيانات على الخادم المضاهاة عبر json ، فسيكون عدد المستخدمين دائمًا واحدًا ، ولن نتمكن من التحقق من جميع الحالات باستخدام عدد مختلف من الصفحات.

ونتيجة لذلك ، يمكننا أن نستنتج أنه إذا أردنا تغيير بذرة مرنة واختبارها ليس بالطرق ، ولكن من خلال الوحدات المنطقية للواجهة ، فإننا بحاجة إلى استخدام شيء ما بين e2e واختبارات الوحدة. هذا هو المكان الذي يأتي فيه الاختبار الضحل (اختبار التكامل) إلى الإنقاذ.

قائمة المصطلحات:

  • المحاكاة هي كائنات لمحاكاة الاستجابات في حالات الاستخدام المختلفة.
  • بذرة هي بذرة أشد غباء دون منطق (يمكنك قراءة مارتن).
  • Karma هو عداء اختبار مدمج في الزاوية (غالبًا ما ينصح باستخدام الدعابة بدلاً من ذلك ، ولكن ليس حول ذلك اليوم).
  • الياسمين هو إطار لوصف الاختبارات في شكل المواصفات (انظر أدناه).
  • المواصفات - امتداد ملف الاختبار (وصف المواصفات في نمط BDD).
  • هو اسم طرق الاختبارات بالياسمين.
  • xit هو اسم الطرق التي لن تعمل.
  • مناسب - إذا كانت هناك طرق بنفس الاسم في المواصفات ، فسيتم إطلاقها فقط.

يعتبر الاختبار الضحل لـ Angular ، وكذلك للأطر الأخرى ، نهجًا لاختبار الوحدة ، عندما يتم تقديم مكون بحجم كبير بما فيه الكفاية بحيث يمكن أن يتواجد كوحدة منفصلة لواجهة المستخدم بوظائفه الخاصة.

على سبيل المثال ، لدينا مكون لتحويل hex -> rgb. يمكننا تقديم هذا المكون فقط ، وإنشاء بذرة لمواقف مختلفة ، وتنفيذ حالات الاستخدام الممكنة لهذا المكون من وجهة نظر المستخدمين النهائيين والتحقق من تشغيل المكون.

دعونا نحاول معرفة مثال (المستودع).

قم بإعداد الفصل للوصول إلى مكونات المكون وفقًا لـ PageObject وأضف مساعدًا إلى جذر المشروع.

مساعد - سيساعد على البحث عن العناصر في المكونات التي تم اختيارها للعرض. حتى نتمكن من جعل الحياة أسهل إذا استخدمنا Angular Material: عندها ستقوم عناصر من النوع select بإنشاء قائمة بخيار في كتلة منفصلة ، ويمكن أن يؤدي البحث عن هذه العناصر إلى غلايات ، ويمكن أن يساعد الغلاف في شكل مساعد.

export class PageObjectBase {

  constructor(private root: HTMLDivElement) { }
  //    input  
  _inputValue(cssSelector: string, value: string) { 
    if (value) {
      this.root.querySelector<HTMLInputElement>(cssSelector).value = value;
      this.root.querySelector<HTMLInputElement>(cssSelector).dispatchEvent(new Event('input'));
    }
    else {
      return this.root.querySelector<HTMLInputElement>(cssSelector).value
    }
  }
  //          
  _buttonClick(cssSelector: string) {
    this.root.querySelector<HTMLButtonElement>(cssSelector).dispatchEvent(new Event('click'));
  }

}

يعد PageObject قالب اختبار آليًا شائعًا. تستخدم لتبسيط الدعم للاختبارات المكتوبة. إذا قمنا بتغيير واجهة المستخدم ، فلن نضطر إلى إعادة كتابة الاختبارات ، فقط قم بتغيير محددات العناصر.


export class ConverterFromHexPageObject extends PageObjectBase {

  constructor(root: HTMLDivElement) {
    super(root)
  }

  hex(text?: string) {
    return this._inputValue('.input-hex', text);
  }

  rgb(text?: string) {
    return this._inputValue('.input-rgb', text);
  }

  clear() {
    this._buttonClick('.btn-clear')
  }

  calc() {
    this._buttonClick('.btn-calc')
  }

}

والاختبارات نفسها:


// ,        api   
const urlToSave = 'http://localhost:4200/save-hex';


//  -   
describe('ConverterFromHexComponent', () => {
  let component: ConverterFromHexComponent;
  let fixture: ComponentFixture<ConverterFromHexComponent>;
  let page: ConverterFromHexPageObject;
  let httpTestingController: HttpTestingController;


  //      ,   
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ConverterModule, HttpClientTestingModule]
    })
      .compileComponents();
    httpTestingController = TestBed.get(HttpTestingController);
  }));


  //  ,   
  beforeEach(() => {
    fixture = TestBed.createComponent(ConverterFromHexComponent);
    component = fixture.componentInstance;
    page = new ConverterFromHexPageObject(fixture.nativeElement);
    fixture.detectChanges();
  });


  //    ,     http 
  afterEach(() => {
    httpTestingController.verify();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should clear', async () => {
    page.hex('112233'); //  input  
    expect(page.hex()).toBe('112233'); // ,    
    await page.clear(); //      
    fixture.detectChanges(); //    
    expect(page.hex()).toBe(''); // ,   clear 
  });

  it('should convert', async () => {
    page.hex('123123');
    expect(page.rgb()).toBe('');
    page.calc();
    const req = httpTestingController.expectOne(urlToSave);
    expect(req.request.method).toEqual('POST');
    expect(req.request.body.hex).toEqual('123123');
    req.flush({});
    await fixture.detectChanges();
    expect(page.rgb()).toBe('rgb(18, 49, 35)');
  });

  it('should convert three-digit hex', async () => {
    page.hex('567');
    expect(page.rgb()).toBe('');
    page.calc();
    const req = httpTestingController.expectOne(urlToSave);
    expect(req.request.method).toEqual('POST');
    req.flush({});
    await fixture.detectChanges();
    expect(page.rgb()).toBe('rgb(85, 102, 119)');
  });

  it('rgb should be empty when entered incorrectly hex', async () => {
    page.hex('qw123we');
    page.calc();
    const req = httpTestingController.expectNone(urlToSave);
    await fixture.detectChanges();
    expect(page.rgb()).toBe('');
  });

});

يبدو أن كل شيء بسيط ، ولكن إليك بعض الملاحظات المثيرة للاهتمام حول اختبار Angular Shallow:

  • تحقق دائمًا من عدم وجود طلبات http غير محجوزة ، سيساعدك ذلك على فهم ما إذا كانت هناك أي طلبات غير ضرورية لوظائفنا.
  • PageObject , .
  • json , .
  • , .
  • .
  • .
  • , session, local, cookie ( ).
  • fake.js.
  • .




Source: https://habr.com/ru/post/undefined/


All Articles