如何模拟模拟服务的getter参数值

时间:2018-11-16 07:10:23

标签: angular typescript unit-testing jasmine

我已经尝试过此SO帖子,但这不是我的情况。

我有一个服务(AnimationService),该服务取决于另一个服务(AnimationStateService)。这个AnimationStateService有一个吸气剂state,我想在测试中模拟它。所以我的测试看起来像这样:

animation.service.spec.ts

describe("AnimationService", () => {

let animationService: SpyObj<AnimationService>;
let animationStateService: SpyObj<AnimationStateService>;

beforeEach(() => {

    const spyAnimationStateService = createSpyObj("AnimationStateService", ["changeStatus"]);

    TestBed.configureTestingModule({
        providers: [
            AnimationService,
            {provide: AnimationStateService, useValue: spyAnimationStateService}
        ]
    });

    animationStateService = TestBed.get(AnimationStateService);
    animationService = TestBed.get(AnimationService);
});

fit("should call changeStatus if status is AnimationStatus.Stopped", () => {
    // Arrange
    // animationStateService.status.and.returnValue(AnimationStatus.Stopped); - Doesn't work
    // spyOnProperty(animationStateService, "status").and.returnValue(AnimationStatus.Stopped); - Doesn't work
    // animationStateService.status = AnimationStatus.Stopped; - Works, but with TSLint error

    // Act
    animationService.start();

    // Assert
    expect(animationStateService.changeStatus).toHaveBeenCalled();
   });
});

animation-state.service.spec.ts

@Injectable()
export class AnimationStateService {

public get status(): AnimationStatus { return this.state.animation.status; }
...
}

当我尝试用以下方法模拟吸气剂时:

animationStateService.status.and.returnValue(AnimationStatus.Stopped);

或:

spyOnProperty(animationStateService, "status").and.returnValue(AnimationStatus.Stopped);

它不起作用。吸气剂根本没有返回我已经设置的值。

此方法有效:

animationStateService.status = AnimationStatus.Stopped;

但是它给了我一个TSLint错误:

Cannot assign to 'status' because it is a constant or a read-only property.

所以到现在为止我还不知道,还有什么我应该尝试正确地模拟吸气剂且没有错误。

1 个答案:

答案 0 :(得分:1)

您应该使用带有第三个 accessType 参数的 spyOnProperty(obj, propertyName, accessTypeopt) → {Spy} 将间谍安装到 getter 方法上。

例如

animation.service.ts

import { Injectable } from '@angular/core';
import { AnimationStateService } from './animation-state.service';

@Injectable()
export class AnimationService {
  constructor(private animationStateService: AnimationStateService) {}
  start() {
    return this.animationStateService.status;
  }
}

animation-state.service.ts

import { Injectable } from '@angular/core';

export enum AnimationStatus {
  Stopped = 'Stopped',
  Started = 'Started',
}

@Injectable()
export class AnimationStateService {
  state = {
    animation: {
      status: AnimationStatus.Started,
    },
  };
  public get status(): AnimationStatus {
    return this.state.animation.status;
  }
}

animation.service.spec.ts

import { TestBed } from '@angular/core/testing';
import {
  AnimationStateService,
  AnimationStatus,
} from './animation-state.service';
import { AnimationService } from './animation.service';

fdescribe('53333050', () => {
  let animationStateService: AnimationStateService;
  let animationService: AnimationService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [AnimationService, AnimationStateService],
    });

    animationStateService = TestBed.get(AnimationStateService);
    animationService = TestBed.get(AnimationService);
  });

  it('should call changeStatus if status is AnimationStatus.Stopped', () => {
    // Arrange
    const statusGetterSpy = spyOnProperty(
      animationStateService,
      'status',
      'get'
    ).and.returnValue(AnimationStatus.Stopped);

    // Act
    const actual = animationService.start();
    expect(actual).toEqual(AnimationStatus.Stopped);

    // Assert
    expect(statusGetterSpy).toHaveBeenCalled();
  });
});

单元测试结果:

enter image description here