I've tried this SO post, but it's not my case.
I have a service (AnimationService
), which is depended on another service (AnimationStateService
). This AnimationStateService
has a getter state
, which I want to mock in my test. So my test looks like this:
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; }
...
}
When I tried to mock the getter with:
animationStateService.status.and.returnValue(AnimationStatus.Stopped);
or with:
spyOnProperty(animationStateService, "status").and.returnValue(AnimationStatus.Stopped);
It doesn't worked. The getter simply doesn't returned the value I've been set.
This approach works:
animationStateService.status = AnimationStatus.Stopped;
but it gives me a TSLint error:
Cannot assign to 'status' because it is a constant or a read-only property.
So at this point I don't know, what else should I try to mock the getter properly and without errors.
You should use spyOnProperty(obj, propertyName, accessTypeopt) → {Spy} with third accessType
parameter to install a spy onto getter
method.
E.g.
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();
});
});
unit test result:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With