Angular 使用http服务调用对组件进行单元测试

Angular 使用http服务调用对组件进行单元测试,angular,unit-testing,Angular,Unit Testing,首先,我是角度测试新手,所以请记住这一点。 我有一个组件在ngOnInit方法中调用服务。方法如下所示: ngOnInit() { this.selectorService.category.subscribe(category => { if (!category) return; this.fieldService.list(category, false).subscribe(fields => { let ra

首先,我是角度测试新手,所以请记住这一点。 我有一个组件在ngOnInit方法中调用服务。方法如下所示:

ngOnInit() {
    this.selectorService.category.subscribe(category => {
        if (!category) return;

        this.fieldService.list(category, false).subscribe(fields => {
            let rangeFields = fields.filter(field => !field.isSpecification);
            let specificationFields = fields.filter(field => field.isSpecification);

            this.fields = specificationFields;

            this.productService.listValidatedRangeProducts(category).subscribe(range => {
                if (!range.length) return;
                this.products = range;
                this.range = this.productModelService.mapProducts(rangeFields, range);
                this.saveForm = this.toFormGroup(range[0]);
            });
        });
    });
}

private toFormGroup(product: any): FormGroup {
    let group: any = {};

    this.fields.forEach(field => {
        group[field.name] = new FormControl(product[field.name]);
    });

    return new FormGroup(group);
}
// convenience getter for easy access to form fields
get f() {
    return this.saveForm.controls;
}
我已经对每个服务设置和工作进行了测试。现在我想为这个组件编写测试。我试过这个:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientTestingModule } from '@angular/common/http/testing';

import { SharedModule } from '@shared';
import { SpecificationsSaveComponent } from './specifications-save.component';
import { ToastrModule, ToastrService } from 'ngx-toastr';

describe('SpecificationsSaveComponent', () => {
    let component: SpecificationsSaveComponent;
    let fixture: ComponentFixture<SpecificationsSaveComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [ReactiveFormsModule, HttpClientTestingModule, SharedModule, ToastrModule.forRoot()],
            declarations: [SpecificationsSaveComponent],
            providers: [ToastrService],
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(SpecificationsSaveComponent);
        component = fixture.componentInstance;
        component.range = [
            {
                gtin: 0,
            },
            {
                gtin: 1,
            },
        ];

        component.fields = [
            {
                id: 0,
                canCopy: false,
                categoryId: 'cameras',
                dataType: 0,
                display: false,
                isSpecification: true,
                name: 'gtin',
                order: 0,
                required: true,
            },
        ];
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });

    it('should save and get next', () => {
        expect(component.saveForm.controls['gtin'].value).toBe(1);
    });

    it('should save and get reset', () => {
        expect(component.saveForm.controls['gtin'].value).toBeNull();
    });
});
saveForm应该在ngOnInit方法中创建,从这一行可以看到:

this.saveForm = this.toFormGroup(range[0]);
因此,在我继续之前,我需要做的似乎是模拟selectorServicefieldServiceproductService。 有人能告诉我怎么做吗

以下是完整的组件:

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';

import { Field } from '@models';
import { SelectorService, ProductModelService } from '@core';
import { ProductService, FieldService } from '@services';

@Component({
    selector: 'app-specifications-save',
    templateUrl: './specifications-save.component.html',
    styleUrls: ['./specifications-save.component.scss'],
})
export class SpecificationsSaveComponent implements OnInit {
    range: any[];
    saveForm: FormGroup;
    fields: Field[];
    submitted: boolean = false;

    private products: any[];

    constructor(
        private fieldService: FieldService,
        private productModelService: ProductModelService,
        private productService: ProductService,
        private selectorService: SelectorService,
    ) {}

    ngOnInit() {
        this.selectorService.category.subscribe(category => {
            if (!category) return;

            this.fieldService.list(category, false).subscribe(fields => {
                let rangeFields = fields.filter(field => !field.isSpecification);
                let specificationFields = fields.filter(field => field.isSpecification);

                this.fields = specificationFields;

                this.productService.listValidatedRangeProducts(category).subscribe(range => {
                    if (!range.length) return;
                    this.products = range;
                    this.range = this.productModelService.mapProducts(rangeFields, range);
                    this.saveForm = this.toFormGroup(range[0]);
                });
            });
        });
    }

    // convenience getter for easy access to form fields
    get f() {
        return this.saveForm.controls;
    }

    onSubmit(): void {
        this.submitted = true;

        if (this.saveForm.invalid) {
            return;
        }

        let categoryId = this.fields[0].categoryId;
        let product = {
            categoryId: categoryId,
        };

        let valid = true;
        this.fields.forEach(field => {
            let value = this.f[field.name].value;
            if (valid) {
                valid = !!value;
            }
            product[field.name] = value;
        });

        console.log(this.fields);
        console.log(product);
        console.log(valid);

        // TODO: save the product

        if (valid) {
            let gtin = product['gtin'];
            let index = 0;

            this.range.forEach((item, i) => {
                if (item.gtin !== gtin) return;
                index = i;
            });

            console.log(gtin);
            console.log(index);

            this.saveForm = this.toFormGroup(this.range[index + 1]);
            this.range.splice(index, 1);
        }

        // TODO: reset the form
    }

    private toFormGroup(product: any): FormGroup {
        let group: any = {};

        this.fields.forEach(field => {
            group[field.name] = new FormControl(product[field.name]);
        });

        return new FormGroup(group);
    }
}

不是一个完整的解决方案,但像这样的。。。你仍然需要做产品服务。我在这里用茉莉花来制作模拟

beforeEach(async(() => {
    //Setup mock selectorService
    const selectorService = {
        category: new BehaviorSubject<Category>(new Category()) //new Cateogry() should be whatever you want category to return
    }
    //Setup mock service with one function, 'list'
    const fieldService = jasmine.CreateSpyObj('fieldService', ['list']) //Create fieldService mock with one function 'list'

    fieldService.list.and.returnValue(of(fields)); //Not sure what type of object should be returned here... whatever type of object is returned form fieldService.list()

    TestBed.configureTestingModule({
        imports: [ReactiveFormsModule, HttpClientTestingModule, SharedModule, ToastrModule.forRoot()],
        declarations: [SpecificationsSaveComponent],
        providers: [ToastrService, {provide: FieldService, useValue: fieldService}, {provide: SelectorService, useValue: selectorService}],
    }).compileComponents();
}));
beforeach(异步(()=>{
//设置模拟选择器服务
常量选择器服务={
category:new BehaviorSubject(new category())//new category()应该是您希望category返回的任何内容
}
//使用一个函数“list”设置模拟服务
const fieldService=jasmine.CreateSpyObj('fieldService',['list'])//使用一个函数'list'创建fieldService mock
fieldService.list.and.returnValue(of(fields));//不确定此处应返回什么类型的对象…从fieldService.list()返回的对象类型
TestBed.configureTestingModule({
导入:[ReactiveFormsModule、HttpClientTestingModule、SharedModule、ToAssetModule.forRoot()],
声明:[规范SAVEComponent],
提供程序:[ToAssetService,{Provider:FieldService,useValue:FieldService},{Provider:SelectorService,useValue:SelectorService}],
}).compileComponents();
}));