Ral*_*alf 7 unit-testing typescript angular
我正在尝试对从组件的 ngOnInit() 函数中的异步服务设置的数组进行单元测试。
export class DashboardComponent implements OnInit {
  todos: Todo[] = [];
  constructor(public todoService: TodoService) {}
  ngOnInit(): void {
    this.todoService.getTodos()
      .then(todos => this.todos = todos.slice(1, 5));
  }
}
当我尝试用这样的函数测试它时:
  it('should load four todos for dashboard', function(done) {
    expect(component.todos.length).toEqual(4);
  });
我收到一个错误,即 0 不等于 4,因为承诺尚未解决。我可以让它工作的唯一方法是公开服务并运行“脏”代码:
  it('should load four todos for dashboard', function(done) {
    var todos = component.todoService.getTodos();
    todos.then(x => {
      expect(x.length).toEqual(6);
      expect(component.todos.length).toEqual(4)
    });
    done();
  });
但肯定有更好、更干净的方法来做到这一点,所以欢迎提出任何改进建议!
编辑 1:在 dbandstra 的提示之后,指向正确的方向,我想出了这个代码:
describe('DashboardComponent', () => {
  beforeEach( async(() => {
    TestBed.configureTestingModule({
      declarations: [
        DashboardComponent, EmptyComponent,
        RouterLinkStubDirective, RouterOutletStubComponent
      ],
      providers: [{provide: TodoService, useClass: FakeTodoService}]
    })
      .overrideComponent(TodoSearchComponent, EmptyComponent)
      .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(DashboardComponent);
        comp    = fixture.componentInstance;
      });
  }));
  beforeEach(() => {
    // TodoService actually injected into the component
    let todoService = fixture.debugElement.injector.get(TodoService);
    let spy = spyOn(todoService, 'getTodos')
      .and.returnValue(Promise.resolve(todos));
    // trigger initial data binding
    fixture.detectChanges();
  });
  it('should load four todos for dashboard', () => {
    fixture.whenStable().then(() => { // wait for async getTodos
      fixture.detectChanges();        // update view with todos
      expect(comp.todos.length).toEqual(4);
    });
  })
});
这就像一个魅力,谢谢!
编辑 2:我也让它与/sf/answers/2761179431/ 中建议的解决方案一起工作,方法是让假服务像这样同步:
class TodoServiceMock{
  private data: Todo[];
  getTodos() {
    let todos = [ ...insert fake data here... ];
    this.data = todos;
    return this;
  }
  then(callback) {
    callback(this.data);
  }
}
小智 0
这是为您提供的解决方案:
dashboard.component.ts:
@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.scss'],
})
export class DashboardComponent implements OnInit {
  /* We don't need to set an empty array here */
  todos: Todo[];
  constructor(private todoService: TodoService) {}
  ngOnInit(): void {
    this.todoService.getTodos()
      .then(todos => this.todos = todos.slice(1, 5));
  }
}
和dashboard.component.spec.ts:
describe('DashboardComponent', () => {
  let component: DashboardComponent;
  let fixture: ComponentFixture<DashboardComponent>;
  let todoService: TodoService;
  const todos = [
    { id: 'id1' },
    { id: 'id2' },
    { id: 'id3' },
    { id: 'id4' },
    { id: 'id5' },
    { id: 'id6' },
  ] as Todo[];
  beforeEach(() => {
    TestBed
      .configureTestingModule({
        declarations: [DashboardComponent],
        providers: [
          /* Stub the TodoService as empty object */
          { provide: TodoService, useValue: {} },
        ],
      })
      .compileComponents();
  });
  /**
   * Creating the component instance in another beforeEach()
   * to decompose module configuration and setting values.
   */
  beforeEach(() => {
    fixture = TestBed.createComponent(DashboardComponent);
    component = fixture.componentInstance;
    /* Injecting the TodoService and mocking used methods. */
    todoService = TestBed.inject(TodoService);
    todoService.getTodos = jasmine.createSpy('getTodos').and.resolveTo(todos);
  });
  it('should create an instance of the component', () => {
    expect(component).toBeTruthy();
  });
  describe('#ngOnInit', () => {
    /* Using fakeAsync for having the ability to wait for async operation. */
    it('should load four todos for dashboard', fakeAsync(() => {
      /* Running ngOnInit by calling the first detection of changes. */
      fixture.detectChanges();
      /**
       * Waiting for .then() method response,
       * because we cannot check the result immediately after running ngOnInit,
       * it's promises, not primitive code.
       */
      tick();
      /**
       * We use toBe() in comparing primitive types.
       * toEqual() is used for comparing not primitive types - objects, arrays, etc.
       */
      expect(component.todos.length).toBe(4);
    }));
  });
});
在 Angular 中学习 Jasmine 的推荐资源: https://codecraft.tv/courses/angular/unit-testing/jasmine-and-karma/
| 归档时间: | 
 | 
| 查看次数: | 3690 次 | 
| 最近记录: |