私はAngularで小さなおもちゃのアプリを構築しています。その中には、次のクラスがあります(ProductDetailComponent
およびProductService
)。このサービスには、製品のhttp GETリクエストを作成するためのメソッドが含まれています。コンパニオンは、製品の詳細を表示し、このサービスを使用して製品情報を取得します。アプリケーション(とそのサービス内のサービス)にHttpModule
を追加した後、私のコンポーネントテストは失敗して、 "エラー:Httpのプロバイダがありません!"と言います。角度:依存関係のないプロバイダ
HttpModule
をインポートした場合、テストは再び合格します。しかし、最初にHttpModule
が必要な理由が混乱しています。なぜなら、これはProductService
の依存関係であり、プロバイダを使用してProductService
を嘲笑しているからです。
私の質問は、なぜテストでは、テスト対象のクラスがそれを使用しないときにこの依存関係が必要だと言われているのですか?
製品detail.component.ts
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute, Params} from "@angular/router";
import {ProductService} from "../product.service";
import {Product} from "../product";
import 'rxjs/add/operator/switchMap';
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
styleUrls: ['./product-detail.component.css'],
providers: [ProductService]
})
export class ProductDetailComponent implements OnInit {
product: Product;
constructor(
private productService: ProductService,
private route: ActivatedRoute,
) { }
ngOnInit() {
this.route.params
.switchMap((params: Params) => this.productService.getProduct(+params['id']))
.subscribe(product => this.product = product);
}
}
product.service.ts
import {Injectable} from "@angular/core";
import {Product} from "./product";
import {Http} from "@angular/http";
import "rxjs/add/operator/toPromise";
@Injectable()
export class ProductService {
private products: Product[];
constructor(private http: Http) { }
getProducts(): Promise<Product[]> {
return this.http
.get('/api/products/')
.toPromise()
.then(response => response.json() as Product[])
.catch(error => {
console.error('An error occurred', error);
return Promise.reject(error.message || error)
});
}
getProduct(id: number): Promise<Product> {
return this.http
.get(`/api/products/${id}`)
.toPromise()
.then(response => response.json() as Product)
.catch(error => {
console.error('An error occurred', error);
return Promise.reject(error.message || error)
});
}
}
製品detail.component.spec.ts:
import {async, ComponentFixture, TestBed} from "@angular/core/testing";
import {ProductDetailComponent} from "./product-detail.component";
import {ActivatedRoute} from "@angular/router";
import {Observable} from "rxjs";
import {ProductService} from "../product.service";
import {Product} from "../product";
import {By} from "@angular/platform-browser";
import {DebugElement} from "@angular/core";
import {HttpModule} from "@angular/http";
describe('ProductDetailComponent',() => {
let component: ProductDetailComponent;
let fixture: ComponentFixture<ProductDetailComponent>;
let debugElement: DebugElement;
let element: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ProductDetailComponent],
//imports: [HttpModule], //un-commenting this fixes the breakages
providers: [{
provide: ActivatedRoute,
useValue: {params: Observable.from([{'id': 1}])},
}, {
provide: ProductService,
useValue: {
getProduct: (id: number) => Promise.resolve(new Product(id, 'Example Product Name', 20))
}
}]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProductDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create',() => {
expect(component).toBeTruthy();
});
it('should be stable',() => {
fixture.whenStable().then(() => {
expect(fixture.isStable()).toBe(true);
});
});
it('should display the title',() => {
fixture.whenStable().then(() => {
debugElement = fixture.debugElement.query(By.css('.name'));
element = debugElement.nativeElement;
expect(element.textContent).toEqual('Example Product Name')
});
});
it('should display the price',() => {
fixture.whenStable().then(() => {
debugElement = fixture.debugElement.query(By.css('.span'));
element = debugElement.nativeElement;
expect(element.textContent).toEqual('$ 20.0')
});
});
});