角度测试:在模拟 ngOnInit 上使用的服务时检测更改的正确方法

问题描述 投票:0回答:1

当我取消对

fixture.detectChanges()
的第一次调用的注释时,测试无法按预期工作。

IA 告诉我:

  1. 在创建组件之前设置模拟:这可确保在创建组件时使用模拟服务。
  2. 设置模拟后触发更改检测:这会强制组件根据更新的模拟数据重新渲染。

我的问题是:

  1. 这是为什么?
  2. 有没有办法强制进行变化检测,而不管输入变化如何?
  3. 如果我想通过
    detectChanges()
    拨打
    beforeEach()
    该怎么办?那么我无法在特定测试中设置模拟?
  4. 在每个特定测试 (
    createComponent
    ) 中调用
    it
    是一个好的做法吗?

OBS:我正在使用 Angular 11。

测试代码:

import { ComponentFixture, TestBed } from '@angular/core/testing';

import { MyComponent } from './my.component';
import { SomeService } from '../services/some.service';

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;
  let compiled;

  beforeEach(async () => {
    const spy = jasmine.createSpyObj('SomeService', ['aMethod']);

    await TestBed.configureTestingModule({
      declarations: [ MyComponent ],
      providers: [
        { provide: SomeService, useValue: spy }
      ]
    })
    .compileComponents();
  });

  it('should show another mock', () => {
    // This code was moved from beforeEach()
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    compiled = fixture.nativeElement;

    // *** MOCK VALUE ISN'T PICKED IF THIS IS UNCOMMENTED ***
    fixture.detectChanges();

    const mock: jasmine.SpyObj<SomeService> = TestBed.inject(SomeService) as jasmine.SpyObj<SomeService>;;
    mock.aMethod.and.returnValue('MOCKED VALUE');

    fixture.detectChanges();

    expect(compiled.querySelector('p').innerHTML).toContain('MOCKED VALUE');
  });
});

组件代码:

import { Component, OnInit } from '@angular/core';
import { SomeService } from '../services/some.service';

@Component({
  selector: 'app-my',
  template: `
    <p>
      myPropIs = {{ propThatReadsFromService }}
    </p>
  `,
  styles: [
  ]
})
export class MyComponent implements OnInit {
  propThatReadsFromService: string = 'not set yet';
  constructor(private someService: SomeService) { }

  ngOnInit(): void {
    this.propThatReadsFromService = this.someService.aMethod() || 'did not pick value from service';
  }
}
angular unit-testing mocking jasmine
1个回答
0
投票

在 beforeEach 上初始化组件,因为其他测试用例可以只使用该组件,这样就消除了代码重复。

然后设置间谍,之后您可以重新创建组件,这保证了组件是用间谍初始化的。

其中

detectChanges
是运行角度变化检测以及反映在 HTML 中的值所必需的。

import { ComponentFixture, TestBed } from '@angular/core/testing';

import { MyComponent } from './my.component';
import { SomeService } from '../services/some.service';

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;
  let compiled;

  beforeEach(async () => {
    const spy = jasmine.createSpyObj('SomeService', ['aMethod']);

    await TestBed.configureTestingModule({
      declarations: [ MyComponent ],
      providers: [
        { provide: SomeService, useValue: spy }
      ]
    })
    .compileComponents();
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    compiled = fixture.nativeElement;
  });

  it('should show another mock', () => {
    const mock: jasmine.SpyObj<SomeService> = TestBed.inject(SomeService) as jasmine.SpyObj<SomeService>;;
    mock.aMethod.and.returnValue('MOCKED VALUE');
    fixture = TestBed.createComponent(MyComponent);
    compiled = fixture.nativeElement;

    fixture.detectChanges();

    expect(compiled.querySelector('p').innerHTML).toContain('MOCKED VALUE');
  });
});
© www.soinside.com 2019 - 2024. All rights reserved.