【问题标题】:How to unit test MatDialog (Angular Material) the correct way?如何以正确的方式对 MatDialog(Angular Material)进行单元测试?
【发布时间】:2019-11-25 15:36:13
【问题描述】:

我正忙于单元测试。而且我有一个 Matdialog 表单 Angular 材料。

我尝试测试了这两个功能:

openEcheqSelectorDialog() {
    this.dialog.open(EcheqSelectorComponent, {
      width: '600px',
      maxHeight: 'calc(100vh - 2em)',
      data: {
        participant: this.participant
      }
    });
  }

  openSchemaSelectorDialog() {
    this.dialog.open(SchemaSendDialogComponent, {
      width: '600px',
      maxHeight: 'calc(100vh - 2em)',
      data: {
        participant: this.participant
      }
    });
  }

这是完整的组件:


export class DetailComponent implements OnInit {
  participant: ParticipantInfoDTO;

  constructor(private dialog: MatDialog, route: ActivatedRoute) {
    this.participant = route.snapshot.data['participant'];
  }

  ngOnInit() {
  }

  openEcheqSelectorDialog() {
    this.dialog.open(EcheqSelectorComponent, {
      width: '600px',
      maxHeight: 'calc(100vh - 2em)',
      data: {
        participant: this.participant
      }
    });
  }

  openSchemaSelectorDialog() {
    this.dialog.open(SchemaSendDialogComponent, {
      width: '600px',
      maxHeight: 'calc(100vh - 2em)',
      data: {
        participant: this.participant
      }
    });
  }
}


但如果我在单元测试中这样做:


import { async, TestBed, ComponentFixture } from '@angular/core/testing';
import { ParticipantModule } from '../../participant.module';
import { ActivatedRoute } from '@angular/router';
import { PARTICIPANT_INFO_DTO } from 'src/app/shared/stubs/participant-info-dto.stub';
import { MatDialog } from '@angular/material/dialog';
import { I18nStub } from 'src/app/shared/stubs/i18n-stub';
import { I18n } from '@ngx-translate/i18n-polyfill';
import { DetailComponent } from './detail.component';
import { RouterTestingModule } from '@angular/router/testing';

describe('DetailComponent', () => {

  let component: DetailComponent;
  let fixture: ComponentFixture<DetailComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        ParticipantModule,
        RouterTestingModule
      ],
      providers: [
        MatDialog,
        { provide: ActivatedRoute, useValue: {
          snapshot: {
            data: {
              participant: PARTICIPANT_INFO_DTO[0]
            }
          }
        }},
        { provide: I18n, useValue: I18nStub }
      ]
    }).compileComponents().then( () => {
      fixture = TestBed.createComponent(DetailComponent);
      component = fixture.componentInstance;
      fixture.detectChanges();
    });
  }));

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

  it('should open the EcheqSelectorComponent in a MatDialog', () => {
    component.openEcheqSelectorDialog();
  });

  it('Should open the SchemaSelectorDialog in a MatDialog' , () => {
    component.openSchemaSelectorDialog();
  });

});


然后在jasmine karma的代码覆盖率。一切似乎都被覆盖了——上面写着 100%。但我认为这不是进行单元测试的正确方法。

所以我的问题是:正确吗?

或者我需要改进什么?

谢谢

这是模板:

<div class="header">
  <h1 class="heading list-heading"><span i18n>Participant</span> - {{ participant.fullName }}</h1>
</div>
<div class="body pulled-up">
  <mat-card class="card-spacing">
    <mat-card-header>
      <mat-card-title i18n>Actions</mat-card-title>
    </mat-card-header>
    <mat-card-content>
      <button mat-raised-button class="button-spacing" (click)="openEcheqSelectorDialog()" i18n>Send echeq</button>
      <button mat-raised-button class="button-spacing" (click)="openSchemaSelectorDialog()" i18n>Send schema</button>
    </mat-card-content>
  </mat-card>
  <mat-card class="card-spacing">
      <mat-card-header>
        <mat-card-title i18n>Overviews</mat-card-title>
      </mat-card-header>
      <mat-card-content>
        <button mat-raised-button class="button-spacing" routerLink="echeq" i18n>Echeqs</button>
        <button mat-raised-button class="button-spacing" routerLink="schema" i18n>Schemas</button>
        <button mat-raised-button class="button-spacing" routerLink="qrcode" i18n>Qrcode scans</button>
      </mat-card-content>
    </mat-card>
</div>

【问题讨论】:

  • 有人有什么建议吗?谢谢
  • 您没有测试第二种和第三种情况。你一定会有所期待。

标签: javascript angular unit-testing karma-jasmine istanbul


【解决方案1】:

我可以给你一些提示来解决这个问题。您需要创建一个spy 并将expect 放在上面。比如:

将对话服务公开,以便您可以轻松地对其进行监视

constructor(public dialog: MatDialog, route: ActivatedRoute) {
    this.participant = route.snapshot.data['participant'];
  }

spec.ts

  it('should open the EcheqSelectorComponent in a MatDialog', () => {
    spyOn(component.dialog,'open').and.callThrough();
    component.openEcheqSelectorDialog();
    expect(component.dialog.open).toHaveBeenCalledWith(EcheqSelectorComponent, {
      width: '600px',
      maxHeight: 'calc(100vh - 2em)',
      data: {
        participant: component.participant
      }
    });
  });

  it('Should open the SchemaSelectorDialog in a MatDialog' , () => {
    spyOn(component.dialog,'open').and.callThrough();
    component.openSchemaSelectorDialog();
    expect(component.dialog.open).toHaveBeenCalledWith(SchemaSendDialogComponent, {
      width: '600px',
      maxHeight: 'calc(100vh - 2em)',
      data: {
        participant: component.participant
      }
    });
  });

让我知道这是否对您有用,或者您是否遇到错误。

【讨论】:

  • 谢谢维韦克。我添加了模板。因为它可以通过单击按钮来工作。那么是否有必要还包括一个可以通过单击按钮来工作的测试?现在覆盖率是 100%。但你的建议是什么?谢谢
  • @savantCodeEngineer :单元测试是关于测试component 的完整性,而不是测试interacts 与其他组件的完整性,这就是我们尝试模拟外部事物的原因。在这种情况下,当 btn 被收集时,您的组件具有打开 MatDialog 的行为。因此,如果此功能已更改并且您的测试没有覆盖它,那么这不是一个很好的覆盖范围。所以,最好在单元测试中检查一下
  • 另外,尝试测试一些重要的 HTML DOM 元素的行为。有时这可能不会增加代码覆盖率,但单元测试的目的是确保组件的功能不会在不知不觉中发生变化。我为 Angular 写了一系列文章(在本页底部),因为这些文章很难在互联网上找到。 medium.com/@shashankvivek.7/…
  • 我在我的组件中使用 keyvalue 管道,所以在测试对话框时我收到错误 keyvalue pipe could not be found ,我已经从 angular/common 导入了 .spec 文件中的 keyvalue 管道,但它不起作用.对此有什么想法吗?
  • HTML - 这是我使用 key 构建代码逻辑的示例代码
    {{data.key}}
猜你喜欢
  • 2021-12-17
  • 1970-01-01
  • 2019-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-02
  • 1970-01-01
  • 2020-05-20
相关资源
最近更新 更多