【问题标题】:Unit test component with mocked service - error具有模拟服务的单元测试组件 - 错误
【发布时间】:2019-06-04 15:28:33
【问题描述】:

我开始在 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"})]

如果有任何提示,我将不胜感激;)

【问题讨论】:

    标签: angular unit-testing jasmine mocking spy


    【解决方案1】:

    非常完整的问题,谢谢!它使我可以将其全部放在StackBlitz 中,以确保我发现您正确面临的问题。 :)

    在 StackBlitz 中,您可以看到所有测试都通过了。为了让它们通过,我只对您所做的进行了一次更改,我更改了您从 mockService.get 返回的值,如下所示:

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

    这样做的原因是您的组件希望在结果对象中有一个带有项目值的“实体”键。注意 - 它还期望有一个“总”键,所以我也添加了它,尽管你没有测试它。

    还有一点需要注意,我在 StackBlitz 中进行了更改以进行演示。虽然您的测试将在您编写它们时全部通过,但您可能不知道 fixture.detectChanges() 实际执行 ngOnInit() - 这让我在之前的测试中绊倒了。为了说明这一点,我修改了您在一个规范中专门调用 component.ngOnInit() 的位置以及在本规范中调用 component.updateItems() 的位置,并将它们替换为 fixture.detectChanges()。当然,两者都可以正常工作,但我指出这一点,因为在某些测试中,您需要在调用ngOnInit() 之前设置模拟以获取有效数据,并将fixture.detectChanges() 放在beforeEach() 以上所有规格都意味着它每次调用每个规范之前都会调用它。

    我希望这会有所帮助。

    【讨论】:

    • 天哪!非常感谢您,您解决了我数小时的痛苦思考、尝试和错误!
    猜你喜欢
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-22
    • 1970-01-01
    • 2015-11-29
    • 2019-05-21
    相关资源
    最近更新 更多