我在 Angular 项目中使用
SignalStore
中的 @ngrx/signals
。
我的商店有
onInit
和 onDestroy
钩子,从商店中注入的依赖项调用方法。
import { signalStore, withHooks } from '@ngrx/signals';
class SomeDependency {
start() {
throw new Error('real implementation not relevant');
}
stop() {
throw new Error('real implementation not relevant');
}
}
const MyStore = signalStore(
withHooks((_store, dependency = inject(SomeDependency)) => ({
onInit() {
dependency.start();
},
onDestroy() {
dependency.stop();
},
})),
);
我可以测试创建商店时是否正确调用
dependency.start()
it('should start dependency when created', () => {
const fakeDependency = { start: jest.fn(), stop: jest.fn() };
TestBed.configureTestingModule({
providers: [MyStore, { provide: SomeDependency, useValue: fakeDependency }],
});
TestBed.inject(MyStore);
expect(fakeDependency.start).toHaveBeenCalledOnce(); // test pass ✅
});
我正在寻找一种方法来测试当商店以某种方式被破坏时是否会调用
dependency.stop()
,但是如何强制商店被破坏?
it('should stop dependency when destroyed', () => {
const fakeDependency = { start: jest.fn(), stop: jest.fn() };
TestBed.configureTestingModule({
providers: [MyStore, { provide: SomeDependency, useValue: fakeDependency }],
});
const store = TestBed.inject(MyStore);
// MISSING: force store descruction here
expect(fakeDependency.stop).toHaveBeenCalledOnce(); // test fail ❌
});
除非持有该商店的主机被摧毁,否则该商店无法被摧毁。
因此,为了测试这个场景,我们创建一个名为
TestingComponent
的组件,它唯一的职责是在提供者数组中包含 MyStore
,通过这样做,我们可以使用 fixture.destroy()
销毁该组件,因为商店是一部分该组件的providers数组中,存储onDestroy
钩子被调用,我们可以测试它。
import { Component, inject } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { signalStore, withHooks } from '@ngrx/signals';
export class SomeDependency {
start() {
throw new Error('real implementation not relevant');
}
stop() {
throw new Error('real implementation not relevant');
}
}
export const MyStore = signalStore(
withHooks((_store, dependency = inject(SomeDependency)) => ({
onInit() {
dependency.start();
},
onDestroy() {
dependency.stop();
},
}))
);
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>Hello from {{ name }}!</h1>
<a target="_blank" href="https://angular.dev/overview">
Learn more about Angular
</a>
`,
})
export class App {
name = 'Angular';
}
bootstrapApplication(App);