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));
}
}
Run Code Online (Sandbox Code Playgroud)
当我尝试用这样的函数测试它时:
it('should load four todos for dashboard', function(done) {
expect(component.todos.length).toEqual(4);
});
Run Code Online (Sandbox Code Playgroud)
我收到一个错误,即 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();
});
Run Code Online (Sandbox Code Playgroud)
但肯定有更好、更干净的方法来做到这一点,所以欢迎提出任何改进建议!
编辑 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);
});
})
});
Run Code Online (Sandbox Code Playgroud)
这就像一个魅力,谢谢!
编辑 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);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 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));
}
}
Run Code Online (Sandbox Code Playgroud)
和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);
}));
});
});
Run Code Online (Sandbox Code Playgroud)
在 Angular 中学习 Jasmine 的推荐资源: https://codecraft.tv/courses/angular/unit-testing/jasmine-and-karma/
| 归档时间: |
|
| 查看次数: |
3690 次 |
| 最近记录: |