模拟服务在Angular/Jasmine/Redux中为每个测试返回的可观测值的变化
我有一个服务返回ngrx选择器公开的值。 组件定义此服务以获取数据。 我正在使用模拟服务为组件编写单元测试,我需要模拟服务为每个单元测试返回不同的值。 我怎样才能做到这一点 组件模拟服务在Angular/Jasmine/Redux中为每个测试返回的可观测值的变化,angular,unit-testing,jasmine,karma-jasmine,ngrx,Angular,Unit Testing,Jasmine,Karma Jasmine,Ngrx,我有一个服务返回ngrx选择器公开的值。 组件定义此服务以获取数据。 我正在使用模拟服务为组件编写单元测试,我需要模拟服务为每个单元测试返回不同的值。 我怎样才能做到这一点 组件 @Component({ selector: 'app-test', templateUrl: './test.component.html', providers: [TestService], }) export class TestComponent { tes
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
providers: [TestService],
})
export class TestComponent {
test$ = this.testService.test$;
test: number;
constructor(private service: TestService) {
service.test$.subscribe(test => this.test = test);
}
}
服务
export class TestService {
test$ = this.store.select(getTestValueFromStore);
constructor(private store: Store<any>){}
}
尝试2:使用主题。因果报应造成错误
“类型“Observable”上不存在属性“next”
因为TestService返回的是可观察对象,而不是主题
class MockTestService {
**test$ = new BehaviourSubject(10);**
}
describe('TestComponent', () => {
let testService: TestService;
beforeEach((() => {
// Define component service
TestBed.overrideComponent(
TestComponent,
{ set: { providers: [{ provide: TestService, useClass: MockTestService }] } }
);
TestBed.configureTestingModule({
declarations: [TestComponent]
})
.compileComponents();
}));
beforeEach(async() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
testService = fixture.debugElement.injector.get(TestService);
fixture.detectChanges();
});
it('should do something when the value returned by the service is 20', fakeAsync(() => {
**testService.test$.next(20);**
tick();
expect(component.test).toEqual(20);
}));
});
试试这样的
describe('TestComponent', () => {
beforeEach((() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
providers: [
{ provide: TestService, useValue: { test$: of(20) } }
]
})
.compileComponents();
}));
beforeEach(async() => {
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
testService = fixture.debugElement.injector.get(TestService);
fixture.detectChanges();
});
it('should do something when the value returned by the service is 20', () => {
expect(component.test).toEqual(20);
});
});
这里不需要使用fakeAsync,因为()的of
是同步发射的
也请考虑订阅<代码> NGUNIIT < /COD> HOOK。构造函数应仅用于依赖项注入。
您在问题中说过希望“模拟服务为每个单元测试返回不同的值”。为此,您必须对组件的定义方式进行一些更改ngOnInit()
,这将执行订阅,并将从可观察对象返回的值存储到组件中。test
。请注意,由于您使用的是()的of
,因此它只会发出一次,然后完成。如果将新值放入testService.test$
,它将不会再次发出testService.test$
的值,并根据需要更改这些值我希望这有帮助 如果您试图测试非组件角度项(即带有服务依赖项的AuthGuard),您将无法使用fixture.detectChanges()技巧,因为您将无法检测组件的更改 在这种情况下,您应该使用间谍:
describe('AuthGuardTest', () => {
let testBed: TestBed;
let authGuard: AuthGuard;
let testService: TestService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [AuthGuard]
});
testBed = getTestBed();
testService = testBed.inject(TestService);
authGuard = testBed.inject(AuthGuard);
});
it('should return 1000', () => {
// Mock the method in your testService to return 1000
spyOn(testService, 'getNumber').and.returnValue(1000);
// Call code that references testService.getNumber() and Assert 1000 was returned
});
it('should return 2000', () => {
// Mock the method in your testService to return 2000
spyOn(testService, 'getNumber').and.returnValue(2000);
// Call code that references testService.getNumber() and Assert 2000 was returned
});
});
有关更多示例,请查看以下教程:
嘲弄和间谍-
单元测试AuthGuard-非常感谢您的帮助。这是基于我问题中的代码工作的,但是如果我想在组件初始化后更改服务返回的值,我如何模拟它?我加了这个,这样你就能明白我的意思了。也许我需要问一个新问题。是的,一定要问一个新问题,这是个好问题。解决方案将涉及重构代码,根据您希望它的行为方式使用主题或行为主题。文档当你设置它的时候,我会用一个主题来重新做StackBlitz,向你展示我的意思。我已经试着让它与行为主题一起工作,它也能工作,但是TypeScript不喜欢模拟服务接口与真实服务不同。我问了一个新问题,关于
fixture.detectChanges
提示!谢谢因此,如果我想在服务返回不同的值时添加另一个测试,我该怎么做?我是否需要在每次测试之前配置测试模块?
describe('AuthGuardTest', () => {
let testBed: TestBed;
let authGuard: AuthGuard;
let testService: TestService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [AuthGuard]
});
testBed = getTestBed();
testService = testBed.inject(TestService);
authGuard = testBed.inject(AuthGuard);
});
it('should return 1000', () => {
// Mock the method in your testService to return 1000
spyOn(testService, 'getNumber').and.returnValue(1000);
// Call code that references testService.getNumber() and Assert 1000 was returned
});
it('should return 2000', () => {
// Mock the method in your testService to return 2000
spyOn(testService, 'getNumber').and.returnValue(2000);
// Call code that references testService.getNumber() and Assert 2000 was returned
});
});