在不影响其他测试用例的情况下,更新某个单元测试的信号值
我有一个来自服务注入的信号,我想测试在该值具有特定属性时的场景。
以下是规格定义:
describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
// This is the spy for the service I'm injecting to get the signal from
let myServiceSpy: Spy<MyService>;
const mockSignalValue = {someProperty: ''};
const mockSignalValueWithExtraProperty = {...mockSignalValue, extraProperty: ''};
beforeEach(async () => {
myServiceSpy = createSpyFromClass(MyService);
Object.defineProperty(myServiceSpy, 'mySignal', {
get: () => signal(mockSignalValue),
configurable: true,
});
await TestBed.configureTestingModule({
imports: [MyComponent];
providers: [
{ provide: MyService, useValue: myServiceSpy },
],
}).compileComponents;
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
});
在组件的实现中,这个信号来自服务:
export class MyComponent {
mySignal: Signal<any> = this.myService.mySignal;
constructor(myService: MyService) {}
}
我想测试当信号具有特定值时,组件的行为是否正确,以及在没有该值时的行为。为了简化本示例,我只测试信号值是否具备某个属性。
没有该属性:
it('should not have the extra property', () => {
expect(component.mySignal.extraProperty).toEqual(undefined);
}
我已经尝试了以下方法来在不影响其他测试的前提下,为这个特定测试更新信号值:
it('should have the extra property', () => {
Object.defineProperty(myServiceSpy, 'mySignal', {
// I've tried with both get & set
get: () => signal(mockSignalValueWithExtraProperty),
configurable: true,
});
spyOnProperty(myServiceSpy, 'mySignal', 'get')
.and.returnValue(signal(mockSignalValueWithExtraProperty));
// Neither of these ways worked to update the signal value for this test
fixture.detectChanges();
expect(component.mySignal.extraProperty).toEqual('');
}
解决方案
我们在 beforeEach 中用信号来初始化服务,随后把它配置成组件的属性,因此对服务信号的修改不会传播到组件。
相反,我们可以在测试用例初始化时初始化一个信号,并将其作为服务中的值。
对于第二个测试用例,我们可以使用 set 方法来修改返回的模拟值,这将解决这个问题。
创建一个用来保存该信号的属性:
let mySignalMock: WritableSignal<any>; // <- changed here!
然后用这个属性来初始化信号,该信号将在每个测试用例中被修改:
beforeEach(async () => {
mySignalMock = signal(mockSignalValue);
myServiceSpy = createSpyFromClass(TestService);
Object.defineProperty(myServiceSpy, 'mySignal', {
get: () => mySignalMock, // <- changed here!
configurable: true,
});
对于第一个测试用例,它将照常通过:
it('should not have the extra property', () => {
expect(component.mySignal().extraProperty).toEqual(undefined);
});
对于第二个测试用例,使用 set 方法修改返回的值。
it('should have the extra property', () => {
mySignalMock.set(mockSignalValueWithExtraProperty); // <- changed here!
fixture.detectChanges();
expect(component.mySignal().extraProperty).toEqual('');
});
完整代码:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { signal, WritableSignal } from '@angular/core';
import {
BrowserTestingModule,
platformBrowserTesting,
} from '@angular/platform-browser/testing';
import { describe, it, expect, beforeAll, vi, Mock, beforeEach } from 'vitest';
import { TestComponent } from '../src/app/footer/test.component';
import { TestService } from '../src/app/footer/test.service';
import { createSpyFromClass, Spy } from '@bugsplat/vitest-auto-spies';
describe('TestComponent', () => {
let component: TestComponent;
let fixture: ComponentFixture<TestComponent>;
let mySignalMock: WritableSignal<any>; // <- changed here!
// This is the spy for the service I'm injecting to get the signal from
let myServiceSpy: Spy<TestService>;
const mockSignalValue = { someProperty: '' };
const mockSignalValueWithExtraProperty = {
...mockSignalValue,
extraProperty: '',
};
beforeAll(() => {
TestBed.initTestEnvironment(BrowserTestingModule, platformBrowserTesting());
});
beforeEach(async () => {
mySignalMock = signal(mockSignalValue);
myServiceSpy = createSpyFromClass(TestService);
Object.defineProperty(myServiceSpy, 'mySignal', {
get: () => mySignalMock, // <- changed here!
configurable: true,
});
await TestBed.configureTestingModule({
imports: [TestComponent],
providers: [{ provide: TestService, useValue: myServiceSpy }],
}).compileComponents();
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', async () => {
expect(component).toBeTruthy();
});
it('should not have the extra property', () => {
expect(component.mySignal().extraProperty).toEqual(undefined);
});
it('should have the extra property', () => {
mySignalMock.set(mockSignalValueWithExtraProperty); // <- changed here!
fixture.detectChanges();
expect(component.mySignal().extraProperty).toEqual('');
});
});
Stackblitz演示
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。