3

我正在尝试使用https://github.com/ngneat/spectator编写一个(相当)复杂的测试 我有一个组件,它在ngOnInit中有 3 个 http 服务。

其中两个很容易模拟,我可以通过两种方式(我认为):

const FieldServiceMock = {
    list: (categoryId: string, specificationOnly: boolean) =>
        of([
            {
                id: 0,
                canCopy: false,
                categoryId: 'cameras',
                dataType: 0,
                display: false,
                isSpecification: true,
                name: 'gtin',
                order: 0,
                required: true,
            },
        ]),
};

const ProductServiceMock = {
    listValidatedRangeProducts: (categoryId: string) =>
        of([
            {
                gtin: 0,
            },
            {
                gtin: 1,
            },
        ]),
};

let spectator: Spectator<SpecificationsSaveComponent>;
const createComponent = createComponentFactory({
    component: SpecificationsSaveComponent,
    imports: [],
    providers: [
        mockProvider(FieldService, FieldServiceMock),
        mockProvider(ProductService, ProductServiceMock)
    ],
});

或者

let spectator: Spectator<SpecificationsSaveComponent>;
const createComponent = createComponentFactory({
    component: SpecificationsSaveComponent
});

beforeEach(() => {
    spectator = createComponent();
    spectator.get(FieldService).list.andReturn(of([
        {
            id: 0,
            canCopy: false,
            categoryId: 'cameras',
            dataType: 0,
            display: false,
            isSpecification: true,
            name: 'gtin',
            order: 0,
            required: true,
        },
    ]));
    spectator.get(ProductService).listValidatedRangeProducts.andReturn(of([
        {
            gtin: 0,
        },
        {
            gtin: 1,
        },
    ]));
});

问题是,我有另一项服务不像其他两项那样工作。该服务如下所示:

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

import { Category } from '@models';

@Injectable({
    providedIn: 'root',
})
export class SelectorService {
    private currentCategoriesSubject: BehaviorSubject<Category[]>;
    private currentCategorySubject: BehaviorSubject<string>;

    public categories: Observable<Category[]>;
    public category: Observable<string>;

    constructor() {
        this.currentCategoriesSubject = new BehaviorSubject<Category[]>(null);
        this.categories = this.currentCategoriesSubject.asObservable();

        this.currentCategorySubject = new BehaviorSubject<string>(null);
        this.category = this.currentCategorySubject.asObservable();
    }

    public setCategories(categories: Category[]): void {
        if (!categories.length) return;
        this.setCategory(categories[0].id);
        this.currentCategoriesSubject.next(categories);
    }

    public setCategory(categoryId: string): void {
        this.currentCategorySubject.next(categoryId);
    }

    public get currentCategory(): string {
        return this.currentCategorySubject.value;
    }

    public add(category: Category) {
        let categories = this.currentCategoriesSubject.value;
        if (!categories) categories = [];

        categories.push(category);

        this.currentCategoriesSubject.next(categories);
        this.currentCategorySubject.next(category.id);
    }

    public remove(categoryId: string) {
        let categories = this.currentCategoriesSubject.value;
        for (var i = 0; i < categories.length; i++) {
            if (categories[i].id === categoryId) {
                categories.splice(i, 1);
            }
        }

        this.currentCategoriesSubject.next(categories);

        if (!categories.length) return;

        this.currentCategorySubject.next(categories[0].id);
    }
}

我需要模拟的部分是 public property category。我不知道如何去嘲笑它。有谁有想法吗?

这是我正在测试的组件的ngOnInit方法:

ngOnInit() {
    console.log(this.selectorService);

    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);
}
4

1 回答 1

2

我能够通过使用第一个选项来解决这个问题:

import { Spectator, createComponentFactory, mockProvider } from '@ngneat/spectator';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { of } from 'rxjs';

import { ToastrModule } from 'ngx-toastr';
import { SharedModule } from '@shared';
import { SelectorService, ProductModelService } from '@core';
import { FieldService, ProductService } from '@services';
import { SpecificationsSaveComponent } from './specifications-save.component';

describe('SpecificationsSaveComponent', () => {
    const SelectorServiceMock = {
        category: of('cameras'),
    };

    const FieldServiceMock = {
        list: (categoryId: string, specificationOnly: boolean) =>
            of([
                {
                    id: 0,
                    canCopy: false,
                    categoryId: 'cameras',
                    dataType: 0,
                    display: false,
                    isSpecification: true,
                    name: 'gtin',
                    order: 0,
                    required: true,
                },
            ]),
    };

    const ProductServiceMock = {
        listValidatedRangeProducts: (categoryId: string) =>
            of([
                {
                    gtin: 0,
                },
                {
                    gtin: 1,
                },
            ]),
    };

    let spectator: Spectator<SpecificationsSaveComponent>;
    const createComponent = createComponentFactory({
        component: SpecificationsSaveComponent,
        imports: [ReactiveFormsModule, HttpClientTestingModule, SharedModule, ToastrModule.forRoot()],
        providers: [
            mockProvider(SelectorService, SelectorServiceMock),
            mockProvider(FieldService, FieldServiceMock),
            mockProvider(ProductService, ProductServiceMock),
        ],
    });

    beforeEach(() => {
        spectator = createComponent();
    });

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

我不知道为什么第二个选项不起作用。我可以看到选择器服务具有正确的值,但由于某种原因,它没有被传递给ngOnInit方法。有人可以解释为什么这两行不起作用吗?

beforeEach(() => {
    spectator = createComponent();
    spectator.get(SelectorService).category = of('cameras');
});
于 2019-11-04T12:58:26.720 回答