简体   繁体   English

如何对 Angular 的 Meta 服务进行单元测试?

[英]How to unit test Angular's Meta service?

My Component is using Angular's Meta service to update a meta tag during ngOnInit .我的组件在ngOnInit期间使用 Angular 的元服务来更新元标记。 I'm using my RegionService to get an app-id and set it with Meta's updateTag method via a template literal.我正在使用我的RegionService来获取 app-id 并通过模板文字使用 Meta 的updateTag方法对其进行设置。 But my unit test is having problems getting the value set by my RegionService in the template literal.但是我的单元测试在获取我的RegionService在模板文字中设置的值时遇到问题。 The test returns the following error:测试返回以下错误:

Expected spy Meta.updateTag to have been called with:
  [ Object({ name: 'apple-itunes-app', content: 'app-id=0123456789' }) ]
but actual calls were:
  [ Object({ name: 'apple-itunes-app', content: 'app-id=undefined' }) ].

How can I modify my test so that it knows the value app-id , set by my template literal ${this.regionService.getAppId()} ?如何修改我的测试,使其知道由我的模板文字${this.regionService.getAppId()}设置的值app-id


my.component.ts我的.component.ts

import { Component, OnInit } from '@angular/core';
import { RegionService } from 'src/services/region.service';
import { Meta } from '@angular/platform-browser';

export class MyComponent implements OnInit {

  constructor(
    private regionService: RegionService,
    private meta: Meta
  ) {}
  
  ngOnInit() {
    this.meta.updateTag({name: 'apple-itunes-app', content: `app-id=${this.regionService.getAppId()}`});
  }

}

my.component.spec.ts我的.component.spec.ts

import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { MyComponent } from './my.component';
import { RegionService } from 'src/services/region.service';
import { Meta } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;
  let regionServiceSpy: jasmine.SpyObj<RegionService>;
  let metaServiceSpy: jasmine.SpyObj<Meta>;

  beforeEach(
    waitForAsync(() => {
      const regionServiceSpyObj = jasmine.createSpyObj('RegionService', ['getAppId', 'retrieveABCRegions', 'retrieveDEFRegions']);
      const metaServiceSpyObj = jasmine.createSpyObj('Meta', ['updateTag']);

      TestBed.configureTestingModule({
        declarations: [MyComponent],
        imports: [RouterTestingModule],
        providers: [
          { provide: RegionService, useValue: regionServiceSpyObj },
          { provide: Meta, useValue: metaServiceSpyObj },
        ],
        schemas: [NO_ERRORS_SCHEMA],
      }).compileComponents();

    regionServiceSpy = TestBed.inject(RegionService) as jasmine.SpyObj<RegionService>;
    metaServiceSpy = TestBed.inject(Meta) as jasmine.SpyObj<Meta>;
    }),
  );

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });


  it('should set app-id to 0123456789 if selectedRegion is FR', () => {
    // arrange

    // act
    regionServiceSpy.selectedRegion = 'FR';

    // assert
    expect(metaServiceSpy.updateTag).toHaveBeenCalledWith({name: 'apple-itunes-app', content: 'app-id=0123456789'});
  });
});

region.service.ts region.service.ts

import { retrieveABCRegions, retrieveDEFRegions} from 'src/regions';

@Injectable({
  providedIn: 'root',
})
export class RegionService {

  selectedRegion: Region;

  getAppId(): string {
    if (retrieveABCRegions().includes(this.selectedRegion)) {
      return '111111111'; 
    } else if (retrieveDEFRegions().includes(this.selectedRegion)) {
      return '0123456789';
    }
  }
}

Since you've replaced the RegionService with a SpyObj mock:由于您已将RegionService替换为SpyObj模拟:

{ provide: RegionService, useValue: regionServiceSpyObj }

the real service is no longer being used in your tests (which is the correct approach because you're not testing that service here).您的测试中不再使用真正的服务(这是正确的方法,因为您没有在这里测试该服务)。

So now you need to define what value the mock service's getAppId() method is going to return.因此,现在您需要定义模拟服务的getAppId()方法将返回的值。 You do that by creating a spy strategy for that method on your spy object.您可以通过在您的 spy 对象上为该方法创建一个 spy 策略来做到这一点。

There are different types of spy strategies you can use, but for your purposes here, probably the simplest is returnValue() :您可以使用不同类型的间谍策略,但出于您的目的,可能最简单的是returnValue()

it('should set app-id to 0123456789 if selectedRegion is FR', () => {
  // arrange

  // act
  // regionServiceSpy.selectedRegion = 'FR'; <--- not needed for this test since real service method not being called
  regionServiceSpy.getAppId.and.returnValue('0123456789'); // <-- define what value mock service's getAppId returns

  // assert
  expect(metaServiceSpy.updateTag).toHaveBeenCalledWith({name: 'apple-itunes-app', content: 'app-id=0123456789'});
});

And note that setting regionServiceSpy.selectedRegion = 'FR' is not needed here since the actual service method is not being called.请注意,此处不需要设置regionServiceSpy.selectedRegion = 'FR' ,因为没有调用实际的服务方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM