Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
模拟服务在Angular/Jasmine/Redux中为每个测试返回的可观测值的变化_Angular_Unit Testing_Jasmine_Karma Jasmine_Ngrx - Fatal编程技术网

模拟服务在Angular/Jasmine/Redux中为每个测试返回的可观测值的变化

模拟服务在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

我有一个服务返回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>){}
}
尝试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()并移出组件的构造函数。如果您这样做,那么您可以控制订阅何时触发,否则它将在创建组件时触发,从而很难为每个单元测试返回不同的值

  • 完成后,您需要小心调用fixture.detectChanges()的位置。。这是因为它将执行
    ngOnInit()
    ,这将执行订阅,并将从可观察对象返回的值存储到
    组件中。test
    。请注意,由于您使用的是()的
    of
    ,因此它只会发出一次,然后完成。如果将新值放入
    testService.test$
    ,它将不会再次发出

  • 一旦设置好了此选项,就可以在调用fixture.detectChanges之前更改
    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
        });
    });