Angular Jest 旁观者在测试另一个服务时模拟服务依赖

问题描述

我正在使用,

Angular CLI:10.2.3

节点:12.22.1

项目构建并运行良好。我现在正在尝试使用 Jest 和 spectator 添加测试。我有以下服务;我正在尝试运行一个非常基本的测试(可以模拟大多数值)。

@Injectable({
    providedIn: 'root'
})
export class BasicAuthService {
  environmentName = '';
  environmentUrl = '';

  constructor(
    private http: HttpClient,private config: ConfigService,//custom service 1
    private runtimeConfig: RuntimeConfigService,// custom service 2
  ) { 
      this.environmentName = runtimeConfig.config.environmentName;
      this.environmentUrl = this.environmentName == "localhost" 
          ? "http://" +  runtimeConfig.config.serviceUrl 
          : runtimeConfig.config.serviceUrl;    
  }
  
  getAuthentication(credentials) {
    let basicAuthHeaderString = 'Basic ' 
      + window.btoa(credentials.username + ':' + credentials.password);
    let headers = new HttpHeaders({'Content-Type': 'application/json'});
    let options = {
      headers: headers
    }
    let envUrl = `${this.environmentUrl}/api/login`
    return this.http.post<any>(envUrl,JSON.stringify(credentials),options)
      .pipe(
        map(
          data => {
          sessionStorage.setItem('authenticatedUser',credentials.username);
          sessionStorage.setItem('token',data.token);
          
          this.config.userGroupData = data.entitlements[0];

          }
        )
      );
  }


}

在构造函数中,它试图根据另一个自定义服务 (this.environmentName) 设置 2 个变量(this.environmentUrlruntimeConfig)。

我正在尝试使用以下内容进行测试:

describe('BasicAuthService',() => {
  let spectator: spectatorService<BasicAuthService>;
  const createService = createServiceFactory({
    service: BasicAuthService,providers: [],imports: [
        HttpClientTestingModule],entryComponents: [],mocks: [ConfigService,RuntimeConfigService]
  });


  beforeEach(() => spectator = createService());

  it('should be logged in',() => {
    
    const runtimeConfigService = spectator.inject<RuntimeConfigService>(RuntimeConfigService);
    const configService = spectator.inject<ConfigService>(ConfigService);
    runtimeConfigService.config = { 
      environmentName: "localhost",serviceUrl : "localhost:8071"
    };     // This also does not work,same error.   
    expect(spectator.service.getAuthentication(createService)).toBeTruthy();
  });

});

这是失败的错误

  ? BasicAuthService > should be logged in

  TypeError: Cannot read property 'environmentName' of undefined

      22 |     private runtimeConfig: RuntimeConfigService,23 |   ) {
    > 24 |     this.environmentName = runtimeConfig.config.environmentName;
         |                                                 ^

运行时配置如下。我尝试初始化这些值但没有帮助。

// RuntimeConfigService
@Injectable({
  providedIn: 'root'
})
export class RuntimeConfigService {

  config: Config;
  
  constructor(private http: HttpClient) {}

  loadConfig() {
  return this.http
    .get<Config>('./assets/runtime-config.json')
    .toPromise()
    .then(config => {
        this.config = config;        
    });
  }
}

export class Config {
  serviceUrl: string;
  environmentName: string;
}

我如何模拟这些服务及其值,以便我可以让这个基本测试工作?

解决方法

我会尝试使用来自观众的 mockProvider 函数。您可以通过这种方式轻松地使用默认值模拟服务。当构造函数中的代码依赖于来自 DI 的某些值时,它会派上用场。

import { mockProvider,... } from '@ngneat/spectator/jest'; 

describe('BasicAuthService',() => {
  let spectator: SpectatorService<BasicAuthService>;
  const createService = createServiceFactory({
    service: BasicAuthService,providers: [
      mockProvider(ConfigService,{
        someFunction: () => someReturnValue; //if needed
      }),mockProvider(RuntimeConfigService,{
        config: {
          environmentName: "localhost",serviceUrl : "localhost:8071"
        }
      })
    ],imports: [HttpClientTestingModule],entryComponents: [],});

  beforeEach(() => spectator = createService());

  it('should be logged in',() => {
    expect(spectator.service.getAuthentication(createService)).toBeTruthy();
  });
});