Инъекционные услуги модульного тестирования

У меня возникли проблемы при выполнении простого модульного теста в моем рабочем пространстве NX. Что я пытаюсь сделать, так это 1) настроить TestBed и 2) внедрить службу. Однако, даже если я использую фиктивную службу с подмостками, тест все равно не проходит, так как внедренная служба называетсяundefined

test.service.ts

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class TestService {
  constructor() { }
}

test.service.spec.ts

import { TestBed } from '@angular/core/testing';
import { TestService } from './test.service';

describe('TestService', () => {
  let service: TestService;
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [ TestService ]
    });
    service = TestBed.inject(TestService);
  });
  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

Кто-нибудь знает, почему это происходит? В чем именно проблема?

Изменить: Да, я знаю, что могу создать макет. Однако проблема все еще кажется мне странной, поэтому я хотел бы разобраться в ней, а не искать обходной путь.

Изменить 2: Использованиеng test <project> --test-file=<filename> напрямую дает те же результаты, что и при использовании NXCLI для выполнения тестов

Изменить 3: я поделился своим кодом на StackBlitz по запросу: https://stackblitz.com/edit/ng-unittest-issue

2 ответа

Я прошел через те же проблемы, когда был undefinedпри тестировании. Здесь мою проблему решили две вещи:

  1. Если вы используете Jest, убедитесь, что вы удалили jest.mock('@angular/core/testing')из вашего кода. Это требовалось в более ранних версиях.
  2. Если у вас есть какие-либо другие инъекции в вашей службе, вы должны добавить их в "поставщики" в разделе TestBed.configureTestingModule.

Вот пример функционального кода и модульного тестирования для простой службы Http, протестированных на Angular 9 и Angular 10:

api.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class ApiService {
  constructor(private http: HttpClient) {}
  baseUrl = 'https://my-api-url.com';

  //api/getId/:id
  getDataById(id: number): Observable<DataSample[]> {
    return this.http.get<DataSample[]>(`${this.baseUrl}/getId/${id}`);
  }
}

export interface DataSample {
  id: number;
  name: string;
}

api.service.spec.ts

import {
  HttpClientTestingModule,
  HttpTestingController,
} from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { ApiService, DataSample } from './api.service';

describe('ShiftDataApiService tests', () => {
  let service: ApiService;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [ApiService],
    });
    service = TestBed.inject(ApiService);
    httpMock = TestBed.inject(HttpTestingController);
  });

  afterEach(() => httpMock.verify());

  it('should return an Observable<DataSample[]>', () => {
    expect(service).toBeTruthy();

    const id: number = 1;
    const mockResult: DataSample[] = [
      {
        id: 1,
        name: 'name1',
      },
      {
        id: 2,
        name: 'name2',
      },
    ];
    const expectedUrl = `https://my-api-url.com/getId/${id}`;

    service
      .getDataById(id)
      .subscribe((res) => expect(res).toBe(mockResult));

    const req = httpMock.expectOne(expectedUrl);
    expect(req.request.method).toBe('GET');
    req.flush(mockResult);
  });
});

Надеюсь, поможет

Я думаю, что это неправильно для получения экземпляра службы, потому что вы не предоставили свою услугу.

Раньше я получал экземпляр, как показано ниже:

TestBed.configureTestingModule({
  providers: [TestService]
});
service = TestBed.inject(TestService);

Я думаю, что проблема связана с вашей конфигурацией TestBed, поэтому я бы подошел к этому так:

import { TestBed } from '@angular/core/testing';
import { TestService } from './test.service';

describe('TestService', () => {
  let service: TestService;
  beforeEach(() => {
   TestBed.configureTestingModule({
     declaration:[], // your component here
     imports: [], 
     providers: [TestService], // your services here   
  });

  service = TestBed.get(TestService); // to get the service instance
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});
Другие вопросы по тегам