angular - 更改模拟服务为 Angular/Jasmine/Redux 中的每个测试返回的可观察值

标签 angular unit-testing jasmine karma-jasmine ngrx

我有一个服务返回由 ngrx 选择器公开的值。 组件定义此服务以获取数据。 我正在使用服务的模拟为组件编写单元测试,我需要模拟服务为每个单元测试返回不同的值。 我怎样才能做到这一点?

组件

@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>){}
}

尝试 1(重置服务的值):不起作用

class MockTestService {
    **test$ = of(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$ = of(20);**

        tick();

        expect(component.test).toEqual(20);
    }));
});

尝试 2:使用主题。 karma 抛出错误 “‘next’属性在‘Observable’类型上不存在” 因为 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);
        }));
    });

最佳答案

您在问题中说过您希望“模拟服务为每个单元测试返回不同的值”。为此,您将不得不对组件的定义方式进行一些更改。

  1. 最重要的变化是将订阅移至 ngOnInit() 并移出组件的构造函数。如果您这样做,那么您可以控制订阅何时触发,否则它将在创建组件时触发,从而很难为每个单元测试返回不同的值。

  2. 完成后,您需要小心调用 fixture.detectChanges() 的地方。这是因为这将执行 ngOnInit(),这将执行订阅并将 Observable 返回的值存储到 component.test 中。请注意,由于您使用的是 of(),因此它只会发出一次然后完成。如果您将新值放入 testService.test$,它不会再次发出。

  3. 设置完成后,您可以在调用 fixture.detectChanges 之前更改 testService.test$ 的值,并根据需要设置值。

我已经设置了一个 StackBlitz为了证明这一点,尽可能少地更改代码以使其正常工作。有两个测试,每个测试返回不同的值。

希望对您有所帮助!

关于angular - 更改模拟服务为 Angular/Jasmine/Redux 中的每个测试返回的可观察值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54176001/

相关文章:

angular - 如何在@ngrx/effects 中等待 2 个 Action

在线 Angular Material 进度微调器

angular - Angular辅助路由懒加载时报错: Cannot match any routes.

unit-testing - 如何保持你的单元测试简单和隔离,同时仍然保证 DDD 不变量?

java - 比较几乎所有字段都相同的对象

c# - Mvc 5 单元测试 - 设置 Controller 的 viewbag 值

java - 如何在 Angular 6 中使用 Spring MVC 的 ModelAndView 响应?

asynchronous - 在 Protractor 中获取请求异步调用

javascript - 如何使用 Jasmine spy 检查 'this' 的值?

javascript - 如何使用 jasmine-node 配置 RequireJS (require.config())?