代码之家  ›  专栏  ›  技术社区  ›  Steven Scott

Stryker/Angular6:从模板应用程序的标准@Component中删除突变体

  •  1
  • Steven Scott  · 技术社区  · 6 年前

    我用Angular6创建了一个基本的模板应用程序 Stryker 变异测试正在进行中。在基本主页上:

    import { Component } from '@angular/core';
    
    /**
    * Home Page Definition
    */
    @Component({
        selector: 'app-home',
        templateUrl: 'home.page.html',
        styleUrls: ['home.page.scss']
    })
    export class HomePage {}
    

    我有本页的基本测试文件:

    import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
    import { async, ComponentFixture, TestBed } from '@angular/core/testing';
    
    import { HomePage } from './home.page';
    
    /**
    * Home Page Test File
    */
    describe('HomePage', () => {
        let component: HomePage;
        let fixture: ComponentFixture<HomePage>;
    
        beforeEach(async(() => {
            TestBed.configureTestingModule({
                declarations: [HomePage],
                schemas: [CUSTOM_ELEMENTS_SCHEMA]
            }).compileComponents();
        }));
    
        beforeEach(() => {
            fixture = TestBed.createComponent(HomePage);
            component = fixture.componentInstance;
            fixture.detectChanges();
        });
    
        it('should create', () => {
            expect(component).toBeDefined();
            expect(component).toBeTruthy();
        });
    
        it('should be proper component', () => {
            expect(component).toBeInstanceOf(HomePage);
        });
    });
    

    虽然这通过并测试将创建主页,但我仍然拥有 Stryker mutation errors

    在basic主页上,@Component有3个字段,它们都是文本,因此都会生成变种幸存者。我不知道如何写一个测试,将杀死这些突变幸存者。

    如果我不能编写测试来处理该条件,Stryker似乎没有方法忽略一段代码作为备用代码。

    1 回复  |  直到 6 年前
        1
  •  4
  •   Lars Gyrup Brink Nielsen    6 年前

    您可以测试组件实例的组件元数据注释,这可以作为执行TDD(测试驱动开发)时的一个起点,但是您应该能够快速地将其替换为验证实际行为的适当测试。

    注意,运行时组件元数据将随着即将到来的Angular Ivy内部重写而更改。

    A StackBlitz demonstrating this spec

    样式

    /* host.page.scss */
    :host {
      display: block;
    
      font-family: Georgia, serif;
    }
    

    <!-- host.page.html -->
    <p>app-home works!</p>
    

    测试套件

    // home.page.spec.ts
    import { Component, DebugElement } from '@angular/core';
    import { async, ComponentFixture, TestBed } from '@angular/core/testing';
    import { By } from '@angular/platform-browser';
    
    import { HomePage } from './home.page';
    
    type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T]
    type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>
    
    type ComponentMetadata = Omit<Component, 'styleUrls' | 'templateUrl'>
    
    @Component({
      template: '<app-home></app-home>'
    })
    class TestHostComponent {}
    
    /**
    * Home Page Test File
    */
    describe('HomePage', () => {
      let component: HomePage;
      let debugElement: DebugElement;
      let hostFixture: ComponentFixture<TestHostComponent>;
      let metadata: ComponentMetadata;
      let nativeElement: HTMLElement;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [
            HomePage,
            TestHostComponent,
          ],
        }).compileComponents();
      }));
    
      beforeEach(() => {
        hostFixture = TestBed.createComponent(TestHostComponent);
        debugElement = hostFixture.debugElement.query(By.css('app-home'));
        component = debugElement.componentInstance;
        nativeElement = debugElement.nativeElement;
        metadata = component['__proto__'].constructor.__annotations__[0];
        hostFixture.detectChanges();
      });
    
      it('should create', () => {
        expect(component).toBeDefined();
        expect(component).toBeTruthy();
      });
    
      it('should be proper component', () => {
        expect(component instanceof HomePage).toBe(true, 'it must be a HomePage');
      });
    
      describe('metadata inspection', () => {
        it('should have proper selector', () => {
          const { selector } = metadata;
    
          expect(selector).toBe('app-home');
        });
    
        it('should have template', () => {
          const { template } = metadata;
    
          expect(template).toContain('app-home works!');
        });
    
        it('should have styles', () => {
          const { styles: [style] } = metadata;
    
          expect(style).toContain('display:block');
          expect(style).toContain('font-family:Georgia');
        });
      });
    
      describe('shallow tests with host component', () => {
        it('should have proper selector', () => {
          expect(nativeElement.tagName).toMatch(/app\-home/i);
        });
    
        it('should have template', () => {
          expect(nativeElement.innerText).toContain('app-home works!');
        });
    
        it('should have styles', () => {
          const styles: CSSStyleDeclaration = getComputedStyle(nativeElement);
          expect(styles.display).toBe('block');
          expect(styles.fontFamily.startsWith('Georgia'))
            .toBe(true, 'it should use the expected font family')
        });
      });
    });
    
    推荐文章