如何单元测试Angular的元服务?

发布于 2025-02-13 18:21:26 字数 3417 浏览 0 评论 0原文

我的组件是在ngoninit期间使用Angular的Meta服务更新元标记。我正在使用我的grounionservice获取App-ID,并通过模板文字使用Meta的UpdateTag方法设置它。但是我的单位测试是在模板字面的我的grounionservice设置的值时遇到问题。该测试返回以下错误:

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' }) ].

我如何修改测试,以便知道值app-id,由我的模板literal $ {this.gregionservice.getAppid()} ?


my.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

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

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';
    }
  }
}

My Component is using Angular's Meta service to update a meta tag during ngOnInit. I'm using my RegionService to get an app-id and set it with Meta's updateTag method via a template literal. But my unit test is having problems getting the value set by my RegionService in the template literal. 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()} ?

my.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

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

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';
    }
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夜还是长夜 2025-02-20 18:21:29

由于您已用gemionservice spyobj模拟:

{ provide: RegionService, useValue: regionServiceSpyObj }

实际服务不再在测试中使用(这是正确的方法,因为您没有测试该测试在这里服务)。

因此,现在您需要定义模拟服务的getAppid()方法将返回什么值。您可以通过在间谍对象上为该方法创建间谍策略来做到这一点。

不同类型的间谍策略最简单的是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'});
});

并注意设置gecionservicespy.seledectegion ='fr'不是在这里需要,因为没有调用实际的服务方法。

Since you've replaced the RegionService with a SpyObj mock:

{ 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. You do that by creating a spy strategy for that method on your spy object.

There are different types of spy strategies you can use, but for your purposes here, probably the simplest is 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文