【问题标题】:Angular 8 Jasmine and karma testing: mocked ngonit promise value is not rendered in the DOMAngular 8 Jasmine 和业力测试:模拟的 ngonit 承诺值未在 DOM 中呈现
【发布时间】:2020-06-01 10:56:32
【问题描述】:

运行测试时,我在测试中的模拟数据不会显示在标记中。无论我尝试什么(fakeasync、done、stubs),运行测试后,promise 的内容都不会呈现在标记中。

谁能告诉我为什么这个模拟的 promise 数据不会显示在 dom 中。我几乎花了 2 天时间,无论我尝试什么,它都无法正常工作。我正在使用 angular 8 并开始认为这是框架中的错误。

我有以下标记:

<div>
    <div class="pt-8">
        <!-- Displays -->
        <ul>
            <li *ngFor="let worker of workers">{{worker.getName()}}</li>
        </ul>

        <!-- DOES NOT DISPLAY -->
        <ol>
            <li *ngFor="let centre of centres">{{centre.name}}</li>
        </ol>
    </div>
</div>

这是课程:

import { Component, OnInit, Input, Inject } from '@angular/core';
import { WorkcentersService } from 'app/services/workcenters.service';
import { Workcenter } from 'app/model/workcenter';
import { User } from 'app/model/user';

@Component({
  selector: 'test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
  workers: User[];
  centres: Workcenter[];

  constructor(private workcentersService: WorkcentersService) { }

  ngOnInit(): void {
    let user1 = new User(); user1.name = "worker 1"; user1.surname = "surname1";
    let user2 = new User(); user2.name = "worker 2"; user2.surname = "surname2";
    let user3 = new User(); user3.name = "worker 3"; user3.surname = "surname3";
    this.workers = [user1, user2, user3];
    this.workcentersService.getWorkcentersList().then(wc => this.centres = wc);
  }
}

这是测试:

import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import { WorkcentersService } from 'app/services/workcenters.service';
import { Workcenter } from 'app/model/workcenter';
import { TestComponent } from './test.component';

fdescribe('TestComponent', () => {
  let component: TestComponent;
  let fixture: ComponentFixture<TestComponent>;

  beforeEach(async () => {
    const mockCentres = createMockCentres();
    const mockWorkcentersService = jasmine.createSpyObj(["getWorkcentersList"]);
    mockWorkcentersService.getWorkcentersList.and.returnValue(Promise.resolve(mockCentres));

    TestBed.configureTestingModule({
      declarations: [TestComponent],
      imports: [],
      providers: [
        { provide: WorkcentersService, useValue: mockWorkcentersService }
      ]
    });

    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
    await fixture.whenStable();
    fixture.detectChanges();
  });

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

  // Passes
  it('should render users', async () => {
    const displayedUsers = fixture.nativeElement.querySelectorAll("ul li");
    expect(displayedUsers.length).toEqual(3);
  });

  // Fails
  it('should render centres', async () => {
    const displayedUsers = fixture.nativeElement.querySelectorAll("ol li");
    expect(displayedUsers.length).toEqual(2);
  });

  // Fails
  it('should display "hello"', fakeAsync(() => {
    fixture.detectChanges();
    tick();
    const displayedUsers = fixture.nativeElement.querySelectorAll("ol li");
    expect(displayedUsers.length).toEqual(2);
  }));

  function createMockCentres(): Workcenter[] {
    const mockCentre1 = new Workcenter();mockCentre1.id = 1;mockCentre1.name = "Test centre 1";
    const mockCentre2 = new Workcenter();mockCentre2.id = 2;mockCentre2.name = "Test centre 2";
    return [mockCentre1, mockCentre2];
  }
});

【问题讨论】:

  • 您希望它出现在哪个测试用例中?你的测试用例失败了吗?
  • 在测试“应该渲染中心”。但是它应该真正呈现在所有这些中。
  • 将其中一个测试用例更改为适合,看看它是否呈现?
  • 你是什么意思?它不会为其中任何一个渲染。
  • 在下面试试我的解决方案。

标签: javascript angular testing jasmine karma-runner


【解决方案1】:
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';

import { AppComponent } from './app.component';
import { WorkCenter } from './workCenter';
import { WorkcentersService } from './workcenters.service';

fdescribe('TestComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;
  let mockWorkcentersService: WorkcentersService;
  beforeEach(async () => {
    const mockCentres = createMockCentres();
    TestBed.configureTestingModule({
      declarations: [AppComponent],
      imports: [],
      providers: [
        WorkcentersService
      ]
    });

    fixture = TestBed.createComponent(AppComponent);
    mockWorkcentersService = TestBed.get(WorkcentersService);
    spyOn(mockWorkcentersService, 'getWorkcentersList').and.returnValue(new Promise((resolve, reject) => resolve(mockCentres)));
    component = fixture.componentInstance;
    await fixture.whenStable();
    fixture.detectChanges();
  });

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

  // Passes
  it('should render users', async () => {
    const displayedUsers = fixture.nativeElement.querySelectorAll('ul li');
    expect(displayedUsers.length).toEqual(3);
  });

  // Fails
  it('should render centres', async () => {
    expect(mockWorkcentersService.getWorkcentersList).toHaveBeenCalled();
    fixture.detectChanges();
    await fixture.whenStable();
    const displayedUsers = fixture.nativeElement.querySelectorAll('ol li');
    expect(displayedUsers.length).toEqual(2);
  });

  // Fails
  it('should display "hello"', fakeAsync(() => {
    fixture.detectChanges();
    tick();
    const displayedUsers = fixture.nativeElement.querySelectorAll('ol li');
    expect(displayedUsers.length).toEqual(2);
  }));

  function createMockCentres(): WorkCenter[] {
    const mockCentre1 = new WorkCenter(); mockCentre1.id = 1; mockCentre1.name = 'Test centre 1';
    const mockCentre2 = new WorkCenter(); mockCentre2.id = 2; mockCentre2.name = 'Test centre 2';
    return [mockCentre1, mockCentre2];
  }
});

这对我有用

证明:-

还尝试运行单个测试用例以向您显示测试中心现在正在显示:-

【讨论】:

  • 这不会编译。 mockWorkcentersService 在哪里实例化?另外,您将如何用模拟替换 WorkcentersService?
  • 但是您仍然没有声明 mockWorkcentersService 所以代码无法编译
  • 现在试试,如果它不起作用,请尝试从 fixture.injector 获取服务
  • @AndyKing 你检查了吗?
  • 它不起作用。 mockWorkcentersService = TestBed.get(WorkcentersService);返回未定义
【解决方案2】:

@Aakash Garg 我已经接受了您的回答,因为您的回答是正确的。

在这方面花了(还)更多时间后,我发现我们以不同方式创建间谍这一事实并没有任何区别。

关键事实是你转身 夹具.detectChanges(); 等待fixture.whenStable(); 我有他们相反的方式。

您还在测试本身中添加了一个fixture.detectChanges(),这也是必要的。附加的 whenStable 调用似乎没有任何区别。

最后我使用了fixture.autoDetectChanges(),它可以在没有fixture.whenStable调用的情况下工作,如下所示:

beforeEach(async () => {
    const mockCentres = createMockCentres();
    const workers = { workers: createMockWorkers(), companyId: 22 };
    const mockWorkcentersService = jasmine.createSpyObj(["getWorkcentersList"]);
    mockWorkcentersService.getWorkcentersList.and.returnValue(Promise.resolve(mockCentres));

    TestBed.configureTestingModule({
      declarations: [CentreAssociateComponent],
      imports: [],
      providers: [
        //WorkcentersService,
        { provide: WorkcentersService, useValue: mockWorkcentersService },
        { provide: MAT_DIALOG_DATA, useValue: workers },
        { provide: MatDialogRef, useValue: {} }
      ]
    });

    fixture = TestBed.createComponent(CentreAssociateComponent);
    fixture.autoDetectChanges();
    component = fixture.componentInstance;

    await fixture.whenStable();
  });

  it('should render centres', async () => {
    const displayedUsers = fixture.nativeElement.querySelectorAll("ol li");
    expect(displayedUsers.length).toEqual(2);
  });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-19
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多