Компонент модульного тестирования с проверенным сервисом - ошибка - PullRequest
0 голосов
/ 09 января 2019

Я начал работать над тестированием компонентов и сервиса в Angular. Я смотрел курс по множественному взгляду и пытался следовать идеям: https://codecraft.tv/courses/angular/unit-testing/mocks-and-spies/ Однако у меня есть проблема с методом тестирования компонента. К сожалению, я не могу найти решение, поэтому решил попросить вас о помощи.

Мой сервис:

@Injectable()
export class MyService {
  private config: AppConfig;
  constructor(private apiService: ApiService, private configService: ConfigurationService) {
    this.config = configService.instant<AppConfig>();
  }

  public get(name: string, take: number = 10, skip: number = 0, params?:any): Observable<any> {
    return this.apiService.post(`${this.config.baseUrl}/${name}/paginated?take=${take}&skip=${skip}`, params);
  }
}

Мой компонент:

 @Component({
  selector: 'my',
  templateUrl: './my.component.html',
  styleUrls: ['./my.component.scss']
})
export class MyComponent implements OnInit {
  @Input("customerId") customerId: string;
  items: CustomerItem[] = [];

  public pagingInfo: PagingMetadata = {
    itemsPerPage: 5,
    currentPage: 1,
    totalItems: 0
  };
  constructor(private service: MyService) { }

  ngOnInit() {
    if (this.customerId) {
      this.updateItems();
    }
  }

  updateItems() {
    let skip = (this.pagingInfo.currentPage - 1) * this.pagingInfo.itemsPerPage;
    let take = this.pagingInfo.itemsPerPage;
    this.service.get("customer", take, skip, { customerId: this.customerId }).subscribe(result => {
      this.items = result.entities;
      this.pagingInfo.totalItems = result.total;
    }, (error) => {
      console.log(error.message);
    });
  }
}

Мой тестовый файл my.component.spec.ts:

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;
  let mockService;
  let ITEMS = [
    {
        "title": "test",
        "id": "5e188d4f-5678-461b-8095-5dcffec0855a"
    },
    {
        "title": "test2",
        "id": "5e188d4f-1234-461b-8095-5dcffec0855a"
    }
]

beforeEach(async(() => {
  mockService = jasmine.createSpyObj(['get']);

  TestBed.configureTestingModule({
    imports: [NgxPaginationModule, RouterTestingModule],
    declarations: [MyComponent],
    providers: [
      { provide: MyService, useValue: mockService }
    ]
  })
    .compileComponents();
}));

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

// works fine
it('should create', () => {
  expect(component).toBeTruthy();
});

// works fine
it('should NOT call updateItems method on initialization', () => {
  component.ngOnInit();
  let spy = spyOn(component, 'updateItems').and.callThrough();

  expect(spy).not.toHaveBeenCalled();
});

// works fine
it('should call updateItems method on initialization', () => {
    component.customerId = "1";
    let spy = spyOn(component, 'updateItems').and.callFake(() => { return null });

    component.ngOnInit();

    expect(spy).toHaveBeenCalled();
  });

// gives error
it('should update items', () => {
  component.pagingInfo.currentPage = 1;
  component.pagingInfo.itemsPerPage = 10;
  component.customerId = "1";
  mockService.get.and.returnValue(of(ITEMS));

  component.updateItems();

  expect(component.items).toBe(ITEMS);
});
});

3 первых теста работают нормально, однако для последних - при обновлении элементов я получил ошибку:

Ожидается, что неопределенным будет [Object ({"title": "test", "id": "5e188d4f-5678-461b-8095-5dcffec0855a"}, {"title": "test2", "id": " 5e188d4f-1234-461b-8095-5dcffec0855a "})]

Буду очень признателен за любые советы;)

1 Ответ

0 голосов
/ 10 января 2019

Очень полный вопрос, спасибо! Это позволило мне поместить все это в StackBlitz , чтобы быть уверенным, что я выяснил проблему, с которой вы столкнулись правильно. :)

В этом StackBlitz вы можете видеть, что тесты теперь все проходят. Я только один раз изменил то, что вы имели, чтобы их передать, я изменил значение, которое вы возвращали из mockService.get, следующим образом:

mockService.get.and.returnValue(of({entities: ITEMS, total: 2}));

Причина этого в том, что ваш компонент ожидает, что в полученном объекте будет ключ «сущностей» со значением элементов. Обратите внимание - он также ожидает, что будет также ключ 'total', поэтому я добавил его также, хотя вы не проверяли его.

Еще одна вещь, которую стоит отметить, которую я изменил в StackBlitz для демонстрации. Хотя все ваши тесты будут проходить так, как вы их написали, вы, возможно, не знаете, что fixture.detectChanges() на самом деле выполняет ngOnInit(), что раньше приводило меня в замешательство при тестировании. Чтобы показать это, я изменил, где вы специально назвали component.ngOnInit() в одной спецификации и где вы назвали component.updateItems() в этой спецификации и заменил их на fixture.detectChanges(). Конечно, оба будут работать нормально, но я указываю на это, потому что в некоторых тестах вам нужно установить mock ДО вызова ngOnInit(), чтобы получить действительные данные, и поставить fixture.detectChanges() в beforeEach() над всеми спецификациями, что означает вызывается каждый раз перед вызовом каждой спецификации.

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

...