【问题标题】:Stryker/Angular6: Remove mutants from standard @Component on template applicationStryker/Angular6:从模板应用程序上的标准@Component 中删除突变体
【发布时间】:2019-01-25 23:38:08
【问题描述】:

我已经使用 Angular 6 创建了一个基本的模板应用程序,我正在尝试让 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);
    });
});

虽然这通过并测试将创建主页,但我仍然有 .

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

如果我无法编写测试来处理这种情况,Stryker 似乎没有一种方法可以忽略一段代码作为替代方法。

【问题讨论】:

    标签: angular mutation-testing stryker


    【解决方案1】:

    您可以测试组件实例的组件元数据注释,这可以作为 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')
        });
      });
    });
    

    【讨论】:

    • 谢谢。这向我展示了我需要什么并纠正了一个问题。对于空 CSS,我必须在 CSS 中放置一个基本元素才能让验证器正常工作,但这应该存在于实际应用程序中。
    • 是的,所有的要点。我们实际上得到了很多这个问题,也是为了忽略这些突变体的可能性。问题是:如果代码没有经过测试,为什么还在那里?您应该对其进行测试,将其删除,或者排除较低的突变分数。可能有充分的理由忽略某些突变行,但这不是其中之一 OMHO。
    • 让我用更多的测试示例回复你,Steven。我认为元数据检查可以作为使用 TDD 的起点,但最终应该用真实的测试来代替。此外,我不确定我们是否可以在所有环境中依赖 __proto____annotations__ 在未来的 Angular 版本中保持其名称。
    • 我在答案和 StackBlitz 中添加了适当的测试,@StevenScott。
    • 我认为这是因为我从第一个 beforeEach 中删除了 async() 调用。我现在加回来了。
    猜你喜欢
    • 2021-11-13
    • 2020-02-02
    • 1970-01-01
    • 2019-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多