Невозможно прочитать свойство length of undefined при модульном тестировании

Я тестирую модуль, который отображает список кодов с сервера.

Ответ приходит в таком формате:

{
  ContactActivityView :[
        {
           Code:"AB",
           IsActive:false,
        },
        {
           Code:"BC",
           IsActive:true,
        }
        ..
        ...
  ]
}

В моем файле component.ts я использую его следующим образом:

codesArray: ICodeModel[];

ngOnInit() {
  this.getCodes();
}

getCodes() {
    this.service.getCodes()
      .subscribe((response: ICodeModel[] | []) => {
        this.codesArray = response['ContactActivityView'];
      },
      error => console.log(error)
    );
}

Он отлично работает, и я могу показать свои данные с помощью файла component.html:

  ..
  ...
    <div  class="message" *ngIf="codesArray.length === 0">
      No Data Found.
    </div>
    <div class="tbl-row" *ngFor="let code of codesArray">
      <div class="item">
        {{ code.Code }}
      </div>
      <div class="item">
        {{ code.IsActive }}
      </div>
  ..
  ...

файл component.service:

..
...
getCodes(): Observable<ICodeModel[]> {
  return this._service.get(this.codeURL);
}
..
...

Теперь, когда я запускаю свой файл component.spec, он выдает ошибку:

TypeError: Cannot read property 'length' of undefined

Я понял, что в .html мой codesArray равен undefined, из-за чего длина undefined.

Я console мой codesArray. Он показывает данные в файле comp.ts, но приходит undefined в файле comp.spec

Не уверен, что я делаю не так, поскольку я могу правильно отобразить данные, но почему-то мой тест не работает. Вот мой файл component.spec

..
...
class MockCodesService {
  getCodes(): Observable<ICodeModel[]> {
    return of([]);
  }

  addCode(param: ICodeModel){
    return of({});
  }

  updateCode(param: ICodeModel) {
    return of({});
  }
}

describe('CodesComponent', () => {
  let component: CodesComponent;
  let fixture: ComponentFixture<CodesComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        CodesComponent
      ],
      providers: [
        { provide: CommonCrudService, useClass: CommonCrudMockService },
        { provide: MessageService, useClass: MessageMockService },
        { provide: AppService, useClass: AppMockService },
        { provide: CodesService, useClass: MockCodesService }
      ],
      schemas: [NO_ERRORS_SCHEMA]
    })
    .compileComponents();
  }));

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

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

Спасибо.


person Mr. A    schedule 20.04.2020    source источник


Ответы (1)


В MockCodesService getCodes() возвращает наблюдаемое из массива, но в вашем компоненте this.service.getCodes() ожидает наблюдаемое от объекта со свойством ContactActivityView. Попробуйте сделать что-нибудь подобное в MockCodesService:

getCodes(): Observable<ICodeModel[]> {
  return of({
    ContactActivityView :[
    {
       Code:"AB",
       IsActive:false,
    },
    {
       Code:"BC",
       IsActive:true,
    }]
  });
}
person alexortizl    schedule 20.04.2020
comment
Спасибо за ответ. Теперь я понимаю. Но тогда в моих данных около 200-300 объектов кода. Так является ли хорошей практикой указывать мои настоящие данные внутри Mock Service? Потому что я чувствую, что должен вызвать настоящий метод моего служения. Можно ли использовать в моём макетном сервисе только скелет моих реальных данных? Пожалуйста, просветите по этому поводу. Спасибо. - person Mr. A; 20.04.2020
comment
@ Мистер А рад помочь. Обычно не рекомендуется тестировать компоненты с помощью реальных сервисов. Смысл модульного теста - проверить ваш компонент изолированным от всего остального, включая службы. Используя макет, вы можете контролировать, что получает ваш компонент, не беспокоясь о реализации службы. Если вам нужно проверить, как ваш компонент ведет себя с более чем 200 объектами, возможно, вы сможете создать функцию, которая генерирует 200+ фиктивных данных в вашем макетном сервисе. Также, если ваша служба обращается к серверу, использующему настоящий сервер, это может замедлить ваши тесты. - person alexortizl; 20.04.2020
comment
Теперь я пытаюсь использовать один объект как: return of ({ContactActivityView: [testObject]}); testObject - один из информационных объектов кода - person Mr. A; 20.04.2020
comment
Но это не помогает :( - person Mr. A; 20.04.2020