我试图理解为什么我的测试没有按预期进行。这是组件:
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [HomeService]
})
export class AppComponent {
title = 'testing-angular';
constructor (private service: HomeService ) {}
CallHomeService(): void {
this.service.DoStuff();
}
}
这里的服务:
@Injectable()
export class HomeService {
constructor() { }
DoStuff(): void {
console.log('homeService has been called')
}
}
我只想检查
DoStuff
是否被调用,所以我做了这个测试:
describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
let appComponent: AppComponent;
let homeServiceMock: jasmine.SpyObj<HomeService>; // Use jasmine.SpyObj type for mock
beforeEach(() => {
// Create a spy object for HomeService
homeServiceMock = jasmine.createSpyObj('HomeService', ['DoStuff']);
TestBed.configureTestingModule({
declarations: [AppComponent],
providers: [{provide: HomeService, useValue: homeServiceMock}] // Provide the spy object directly
});
fixture = TestBed.createComponent(AppComponent);
appComponent = fixture.componentInstance;
});
it('should call DoStuff() when CallHomeService() is called', () => {
// Call the CallHomeService() method of AppComponent
appComponent.CallHomeService();
// Expect that DoStuff() was called on the mock HomeService
expect(homeServiceMock.DoStuff).toHaveBeenCalled(); // Use toHaveBeenCalled() matcher
});
});
但我明白了
AppComponent should call DoStuff() when CallHomeService() is called FAILED
Expected spy HomeService.DoStuff to have been called.
at <Jasmine>
at UserContext.apply (src/app/app.component.spec.ts:28:37)
at _ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:375:26)
at ProxyZoneSpec.onInvoke (node_modules/zone.js/fesm2015/zone-testing.js:287:39)
at _ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:374:52)
所以我尝试使用 TestBed.overrideProvider 并且它起作用了:
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { HomeService } from './service/home.service';
describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
let appComponent: AppComponent;
let homeService: jasmine.SpyObj<HomeService>; // Use jasmine.SpyObj type for mock
beforeEach(() => {
// Create a mock object for HomeService
const homeServiceMock = jasmine.createSpyObj('HomeService', ['DoStuff']);
TestBed.configureTestingModule({
declarations: [AppComponent],
providers: []
});
// Override the provider for HomeService with the mock
TestBed.overrideProvider(HomeService, { useValue: homeServiceMock });
fixture = TestBed.createComponent(AppComponent);
appComponent = fixture.componentInstance;
});
it('should call DoStuff() when CallHomeService() is called', () => {
// Call the CallHomeService() method of AppComponent
appComponent.CallHomeService();
// Expect that DoStuff() was called on the mock HomeService
expect(homeService.DoStuff).toHaveBeenCalled();
});
});
我看到 here 如果我在 ts 组件中使用
providers
它将覆盖我的间谍,但我仍然不明白为什么我的 useValue 被覆盖。不应该只在providers
的TestBed.configureTestingModule
提供mock服务,用useValue
来调用mock服务吗?感谢您的帮助。
由于您通过组件的
HomeService
数组向组件提供 providers
,因此该组件没有获得在模块级别创建的 HomeService
的实例——您用 useValue
替换的实例——它获得了自己的实例,单独的实例。
来自文档:
Angular DI 具有分层注入系统,这意味着嵌套的注入器可以创建自己的服务实例。每当 Angular 创建一个组件的新实例,该实例具有在 @Component() 中指定的提供者时,它也会为该实例创建一个新的子注入器。
子模块和组件注入器相互独立,并创建自己独立的提供服务实例。