【问题标题】:Angular Test with mockedService doesn't return the mocked Data带有 mockedService 的 Angular 测试不返回模拟数据
【发布时间】:2020-10-13 11:43:00
【问题描述】:

显然,我仍然缺少对模拟服务的重要理解,我很乐意提供一些意见。

我想在我的组件中测试的代码是:

modulesToDisplay: any[] = [];

...

getModules() {
  this.configService.getModulesToDisplay().subscribe(modules => {
    this.modulesToDisplay = modules;
    }
  );
}

我想测试当我从服务中获取某些内容时是否重新分配了 modulesToDisplay。因此,在我的 Testfile 中,我创建了一个 serviceMock,它返回一个包含两个项目的数组

let configServiceMock: any;

...

beforeEach(async(() => {
  configServiceMock = jasmine.createSpyObj('ConfigService', ['getModulesToDisplay']);
  configServiceMock.getModulesToDisplay.and.returnValue( of(['firstmodule', 'secondmodule']) );

  ...

providers: [
        { ConfigService, useValue: configServiceMock }
      ]
    }).compileComponents();

  beforeEach(() => {
    fixture = TestBed.createComponent(SomeComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

    it('should assign result to modulesToDisplay', () => {
    component.getModules();
    expect(component.modulesToDisplay.length).toBeGreaterThan(0);
  });
...

我希望这个测试能够通过,因为我认为调用 'component.getModules();'在我的测试中将使用模拟数据。但它没有,modulesToDisplay 仍然是我在组件中初始化的空数组。所以我想我还是没有理解 mocking 数据的正确原理。

【问题讨论】:

    标签: javascript angular typescript unit-testing karma-jasmine


    【解决方案1】:

    即使of 应该发出你的模拟值,我怀疑你可能仍然需要在异步上下文中执行它。如果您将规范更改为:

    it('should assign result to modulesToDisplay', fakeAsync(() => {
      component.getModules();
      flushMicrotasks();
      fixture.detectChanges();
      expect(component.modulesToDisplay.length).toBeGreaterThan(0);
    }));
    

    通常当我的模拟似乎没有被使用时,它与我提供给配置的模拟对象与提供给 TestBed.configureTestingModule 的对象不匹配有关。

    我尝试了两种方法来解决这个问题。

    1.) 不要使用useValue 构建提供程序,而是像这样切换到useFactory

    ...
    providers: [{ provide: ConfigService, useFactory: () => configServiceMock }]
    

    2.) 另一种方法是在服务配置完成后获取服务进行测试:

    const csMock = jasmine.createSpyObject('ConfigureService', [...]);
    
    TestBed.configureTestingModule(
    ...
    providers: [{ provide: ConfigureService, useValue: csMock }]
    );
    configServiceMock = TestBed.get(ConfigureService);
    

    【讨论】:

    • 没有成功 :( - modulesToDisplay 仍然是空数组
    • 我添加了一个调用来检测规范的更改,但我看不出它实际上有什么帮助。您能否确认在执行it 时该服务已被模拟?我经常用console.log检查这种事情。
    • 嗯。模拟服务似乎有问题。如果我将我的规范文件更改为: ... }).compileComponents(); configService = TestBed.inject(ConfigService); configService.getModulesToDisplay = () => of(['test1', 'test2']); ......它有效 - 但我仍然没有真正得到区别
    • 如果你把它改成: spyOn(configService, 'getModulesToDisplay').and.returnValue(of['test1', 'test2']);它是否按预期工作?我的猜测是您的模拟实际上并没有被使用。有时我发现更改提供程序以使用 `useFactory: ()=> configServiceMock 有助于或在配置测试模块后使用 configService = TestBed.get(ConfigService) 获取服务可确保您正在测试的对象与提供给您的班级。 HTH
    • 我更新了我的回复以反映这些想法。很难理解你的配置缺少什么,所以我真的只是告诉你我修复麻烦规范的方法。
    【解决方案2】:

    Mocking 非常直接。让我帮你:

    
    beforeEach(async(() => {
      ...
    
      providers: [
            { ConfigService, useClass: MockConfigService}
          ]
        }).compileComponents();
    
      beforeEach(() => {
        fixture = TestBed.createComponent(SomeComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });
    
      it('should assign result to modulesToDisplay', () => {
        component.getModules();
        expect(component.modulesToDisplay.length).toBeGreaterThan(0);
      });
    
    
    
    

    模拟课

    export class MockConfigService{
       getModulesToDisplay(){
         return of({
             // whatever module object structure is
         })
       }
    }
    
    

    这就像一个魅力。我强烈推荐你this article which has a real world example to test a component。对于基础知识,this article would be helpful

    【讨论】:

    • 还有这个:抱歉我的延迟回答。我花了一些时间尝试所有这些不同的方法。你的回答很好!感谢您的方法
    • 感谢您的意见。在这个问题上,我接受了侄子的答案作为正确的答案,因为他的工作解决了我的设置问题
    猜你喜欢
    • 2022-11-28
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-20
    相关资源
    最近更新 更多