简体   繁体   English

Angular 测试 - 如何使用扩展基类测试数据服务

[英]Angular Testing - how to test Data Service with extended base class

I'm having a hard to setup Tests of my Data Services, I'm trying to use the HttpClientTestingModule as defined in these articles Testing with the Angular HttpClient API , from this SO Question and also tried inject from this article Testing HttpClient but I can't get it to work.我很难设置我的数据服务的测试,我正在尝试使用这些文章中定义的HttpClientTestingModule使用Angular HttpClient API 进行测试,来自这个SO 问题,并且还尝试从这篇文章中inject测试 HttpClient但我可以不让它工作。

I believe my problems comes from the fact that I have a global DataService which uses 3 service providers ( HttpClient , NGXLogger and TranslateService from ngx-translate ).我相信我的问题来自这样一个事实,即我有一个使用 3 个服务提供程序的全局DataService (来自ngx-translate HttpClientNGXLoggerTranslateService )。 Then I have multiple Data Services which extends the global DataService like so然后我有多个数据服务扩展了全球DataService像这样

@Injectable()
export class UserDataService extends DataService {
  constructor(protected http: HttpClient, protected logger: NGXLogger, protected translate: TranslateService) {
  super(http, logger, translate);
  this.url = `api/users`;
}

getUsers(): Observable<Users[]> {
  return super.getAll<User[]>(this.url);
}

So as you can see, each extended data services (like UserDataServices ) takes care of injecting the 3 necessary dependencies to the super call.如您所见,每个扩展数据服务(如UserDataServices )负责将 3 个必要的依赖项注入到super调用中。

I'm trying to code my test, which is done with Jest , with the following code我正在尝试使用以下代码编写我的测试,这是使用Jest完成的

describe('User Data Service', () => {
  let dataService: TemplateDataService;
  let httpTestingController: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        HttpClientTestingModule,
        TranslateModule.forRoot(),
        LoggerModule.forRoot({ level: NgxLoggerLevel.ERROR, serverLoggingUrl: 'api/logging', serverLogLevel: NgxLoggerLevel.ERROR }),
      ],
      providers: [
        UserDataService
      ]
    });
    dataService = TestBed.get(UserDataService);
    httpTestingController = TestBed.get(HttpTestingController);
  });

it('should return an Observable<User[]>', () => {
  const dummyUsers = [
    { login: 'John' },
    { login: 'Doe' }
  ];

  dataService.getAll().subscribe((users: User[]) => {
    expect(users.length).toBe(2);
    expect(users).toEqual(dummyUsers);
  });

  const req = httpTestingController.expectOne(`api/users`);
  expect(req.request.method).toBe('GET');
  req.flush(dummyUsers);
});

and it keeps throwing the following error它不断抛出以下错误

Unexpected value 'HttpClientModule' imported by the module 'HttpClientTestingModule'. Please add a @NgModule annotation.

I also tried with this piece of code, but I get the same error我也试过这段代码,但我得到了同样的错误

it(
  'should get users',
  inject(
    [HttpTestingController, NGXLogger, TranslateService, DataService],
    (
      httpMocker: HttpTestingController,
      logger: NGXLogger,
      translate: TranslateService,
      dataServicer: DataService
    ) => {
      // ...our test logic here
    }
  )
);

I'm fairly new to Unit Testing (I started last week) and I'm totally blocked with testing any of my Data Services (on the bright side, I'm ok with testing the component with a data service mock, but I'd like to test these data services as well).我对单元测试相当陌生(我上周开始)并且我完全无法测试我的任何数据服务(从好的方面来说,我可以使用数据服务模拟测试组件,但是我”我也想测试这些数据服务)。

On the technology side, the project uses Angular: ^7.2.10 and jest: ^23.6.0 .在技​​术方面,该项目使用Angular: ^7.2.10jest: ^23.6.0

EDIT编辑

I forgot to mention that DataService is also a Service and I also tried to add it to the providers in the beforeEach() and I still get the same error ( Unexpected value 'HttpClientModule'... ).我忘了提到DataService也是一个服务,我也尝试将它添加到beforeEach()providers ,但我仍然遇到相同的错误( Unexpected value 'HttpClientModule'... )。 As shown below如下所示

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [
      HttpClientTestingModule,
      TranslateModule.forRoot(),
      LoggerModule.forRoot({ level: NgxLoggerLevel.ERROR, serverLoggingUrl: 'api/logging', serverLogLevel: NgxLoggerLevel.ERROR }),
    ],
    providers: [
      DataService,
      UserDataService
    ]
  });
});

Also to give a bit more overview of the DataService , here's a strip down version of it.另外,为了对DataService更多概述,这里是它的精简版。

export class DataService {
  constructor(protected http: HttpClient, protected logger: NGXLogger, protected translate: TranslateService) {}

  get<T>(id?: string, options?: HttpOptions): Observable<T> {
    const caller = findCaller(new Error());
    const uriWithId = id ? `/${id}` : '';
    const requestUrl = this.addGlobalQueryParams(`${this.url}${uriWithId}`);
    this.logger.debug(`DataService - GET method [${caller}] - START - URL:: ${requestUrl}`);

    return this.http.get<T>(requestUrl, options).pipe(map((response: any) => {
      this.logger.debug(`DataService - GET method [${caller}] - END - URL:: ${requestUrl} - Response:: `, response);
      return response;
    }));
  }

  getAll<T>(url?: string, options?: HttpOptions): Observable<T> {
    const caller = findCaller(new Error());
    if (url) {
      this.logger.debug(`DataService - POST method [${caller}] - START - URL:: `, url);
      return this.http.post<T>(url).pipe(map((response: any) => {
        this.logger.debug(`DataService - POST method [${caller}] - END - URL:: ${url} - Response:: `, response);
        return response;
      }));
    }
  }
}

EDIT 2编辑 2

I guess what I'm looking for is how to Unit Test an Extended Class, which was actually asked in the Angular repo here but was never answered and closed because it wasn't an issue but more of a question.我想我要的是如何进行单元测试的扩展级,这实际上是要求在角回购这里,但从来没有回答关闭,因为它不是一个问题,但更多的是问题。

Firstly, you shouldn't need to do the following in your test.首先,您不需要在测试中执行以下操作。

 providers: [
   UserDataService
 ]

Since you are testing the UserDataService itself, doing the following after setting the TestBed should be enough.由于您正在测试UserDataService本身,因此在设置 TestBed 后执行以下操作就足够了。

dataService = TestBed.inject(UserDataService); //TestBed.get(UserDataService);

The other thing to change would be making your base class injectable.另一件要更改的事情是使您的基类可注入。

@Injectable()
export class DataService {...}

I know it sounds stupid, but apparently angular DI seems to need that too.我知道这听起来很愚蠢,但显然角度 DI 似乎也需要这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM