I am trying to do simple test when user click on button it should call method from service. But I am still getting just that method is not called. Component.ts
@Component({
...
providers: [MyService]
})
export class MyComponent implements OnInit, OnDestroy {
constructor(public myService: myService) { }
}
Component.html
<button id="myId"
(click)="myService.myMethodX()">
</button>
MyService.ts
@Injectable()
export class MyService {
constructor() { }
myMethodX(){
...
}
}
And in jasmine I am testing it like this.
const mySpyObj = jasmine.createSpyObj('MyService', ['myMethodX']);
it('...', () => {
// Given
const button = ...
// When
button.click();
fixture.detectChanges();
// Then
expect(mySpyObj.myMethodX).toHaveBeenCalled();
});
but it says that its not called what I am doing wrong?
CodePudding user response:
You have to inject your mock into the test scenario, right now you are using real implmenetion. Normally you would do it via providers
on the TestBed#configureTestModule
but you have your service to be "component" scoped not singleton, thus you must override that as well.
Here you have working example.Pay attention to the comments and especially overrideComponent
call. It has crucial impact as without it real implementation is beeing used instead of our mock.
// your service
@Injectable()
class FooBar {
foo() {
return 'bar';
}
}
//your component
@Component({
template: `
<button (click)="fooBar.foo()"></button>
`,
providers: [FooBar] // FooBar is in scope of component, not singleton, therfore....
})
class FooBarComponent {
constructor(public fooBar: FooBar) {
}
}
describe('Foobar', async () => {
let fooMock: SpyObj<FooBar>;
beforeEach(async () => {
fooMock = createSpyObj<FooBar>(['foo']);
return TestBed.configureTestingModule({
declarations: [FooBarComponent],
}).overrideComponent(FooBarComponent, {
set: { // ..... threfore we are overriding component scope provider - now our mock will be provided instead of real implementation
providers: [
{provide: FooBar, useValue: fooMock} // here you actually start using your mock inside component
]
}
}).compileComponents();
});
//passes without a problems
it('calls foo() on click', () => {
const fixture = TestBed.createComponent(FooBarComponent);
fixture.detectChanges();
fixture.debugElement.query(By.css('button')).nativeElement.click();
expect(fooMock.foo).toHaveBeenCalled();
});
});
CodePudding user response:
Method called myMethodX
from your component is not a method of the service. Inside of that method service method is called (I assume), for example myService.calculate()
.
What you should spy on and test is that method from service. You can do something like this:
// Arange
spyOn(myService, 'calculate');
// Act
button.click();
// Assert
expect(myService.calculate).toHaveBeenCalled();
Second approach would be to test if method of a component is called:
// Arange
spyOn(component, 'myMethodX');
// Act
button.click();
// Assert
expect(component.myMethodX).toHaveBeenCalled();