【问题标题】:"Cannot read property 'length' of undefined" when unit testing单元测试时“无法读取未定义的属性‘长度’”
【发布时间】:2020-04-20 05:44:26
【问题描述】:

我正在对从服务器呈现代码列表的组件进行单元测试。

响应的格式如下:

{
  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 中我的 codesArrayundefined,因为长度是 undefined

console 我的codesArray。它在 comp.ts 文件中显示数据,但在 comp.spec 文件中出现undefined

不确定我做错了什么,因为我能够正确呈现数据,但不知何故我的测试失败了。 这是我的 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();
  });
});

谢谢。

【问题讨论】:

    标签: angular unit-testing jasmine karma-jasmine angular-test


    【解决方案1】:

    MockCodesService getCodes() 从数组中返回一个可观察对象,但在您的组件中this.service.getCodes() 期望来自具有ContactActivityView 属性的对象的可观察对象。尝试在MockCodesService 中做这样的事情:

    getCodes(): Observable<ICodeModel[]> {
      return of({
        ContactActivityView :[
        {
           Code:"AB",
           IsActive:false,
        },
        {
           Code:"BC",
           IsActive:true,
        }]
      });
    }
    

    【讨论】:

    • 感谢您的回复。现在我明白了。但是我的数据中有大约 200-300 个代码对象。那么在模拟服务中指定我的真实数据是一个好习惯吗?因为我觉得那时我必须调用我的服务的真正方法。是否可以在我的模拟服务中仅使用我的真实数据的骨架?请对此有所启发。谢谢。
    • @Mr.A 很高兴为您提供帮助。通常,使用真实服务测试您的组件并不是一个好习惯。单元测试的重点是测试您的组件与其他所有内容(包括服务)隔离。使用模拟你可以控制你的组件得到什么,而不用担心服务的实现。如果您需要测试您的组件如何处理 200 多个对象,您可以创建一个函数,在您的模拟服务中生成 200 多个虚拟数据。此外,如果您的服务使用真实服务器调用服务器,可能会减慢您的测试速度。
    • 现在我正在尝试使用单个对象作为: return of( { ContactActivityView : [testObject] } ); testObject 是代码信息对象之一
    • 但是这个没有帮助:(
    猜你喜欢
    • 2021-12-02
    • 2018-07-01
    • 2018-04-18
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    • 2019-12-30
    • 2017-06-16
    相关资源
    最近更新 更多