问题
After ng test
Expected output: i get pass/fail on x amount of tests.
Actual ouput:
ERROR in src/app/todo-data.service.spec.ts(19,45): error TS2345: Argument of type 'Todo[]' is not assignable to parameter of type 'Expected<Observable<Todo[]>>'.
Type 'Todo[]' is not assignable to type 'ObjectContaining<Observable<Todo[]>>'.
Property 'jasmineMatches' is missing in type 'Todo[]'.
In my todo class i don't have a jasminematches property, but this might not be the root problem.
todo.ts:
export class Todo {
id: number;
title: string = '';
complete: boolean = false;
constructor(values: Object = {}) {
Object.assign(this, values);
}
}
todo-data.service.spec.ts
import {TestBed, async, inject} from '@angular/core/testing';
import {Todo} from './todo';
import {TodoDataService} from './todo-data.service';
...
describe('#getAllTodos()', () => {
it('should return an empty array by default', inject([TodoDataService],
(service: TodoDataService) => {
expect(service.getAllTodos()).toEqual(<Todo[]>[]);
}));
...
todo-data.service.ts
import { Injectable } from '@angular/core';
import { Todo } from './todo';
import { ApiService } from './api.service';
import { Observable } from 'rxjs';
...
export class TodoDataService {
constructor(private api: ApiService) { }
getAllTodos(): Observable<Todo[]> {
return this.api.getAllTodos();
}
...
Please advise how to start deconstructing this error in order to write a correct test.
回答1:
Your getAllTodos function returns an observable and not an array of todos. I think this is why an error occurs. Therefore I think you should write your test differently:
service.getAllTodos().subscribe(todos => {
expect(todos).toEqual([])
});
Also (if you haven't already) you probably want to provide a a stub (mock) for your api service. You should test this service in it's own file.
In your testfile below describe but before you make your testBed (or in a separate file from which you can import it):
const dummyTodos = [];
const mockApiService = {
getAllTodos() {
return Observable.of(dummyTodos);
}
};
In your TestBed.configureTestingModule add the line:
providers: [{provide: ApiService, useValue: mockApiService}],
You can also decide to change the value of the dummyTodos in your tests to check for different responses.
回答2:
I came to the same conclusion of the previous poster. Your initial test assertion is comparing a pending Http request (represented as an observable stream with a single observable) to the expected response of an empty `Todo[]' array.
In the code snippet below, the .subscribe
method activates the observable stream. Placing it inside of a fakeAsync
zone simulates the passage of time in the same way that an asynchronous Http
request behaves. Since the test assertion is inside the subscribe
block, you are now dealing with a completed observable stream and are able to access the contents of the stream, i.e., Todo[]
.
it('should return an empty array by default', fakseAsync(inject([TodoDataService],
(service: TodoDataService) => {
service.getAllTodos().subscribe(success => {
expect(success).toEqual(<Todo[]>)
});
))
);
One behavior in your test that I don't quite understand is your TodoService
appears to delegate Http
handling to an ApiService
that returns Observable<Todo[]>
and your TodoService
also returns Observable<Todo[]>
. If there's a meaningful layer of abstraction between these two services, then I'd defer to the testing method with a MockApiService
outlined in the initial answer.
Alternatively, you could collapse your ApiService
and TodoService
into a single level and make additional assertions about the expected behavior (the mechanics of testing/simulating the Http
backend will depend on whether you are using the Http
methods in @angular/http
or @angular/common/http
).
来源:https://stackoverflow.com/questions/50678582/property-jasminematches-is-missing-in-type-x