如何在 (jasmine + karma) 中为以下方法编写测试,该方法在构造函数中注入了 ComponentFactoryResolver 和 ApplicationRef
Posted
技术标签:
【中文标题】如何在 (jasmine + karma) 中为以下方法编写测试,该方法在构造函数中注入了 ComponentFactoryResolver 和 ApplicationRef【英文标题】:How do I write a test for the following method in (jasmine + karma) that has ComponentFactoryResolver & ApplicationRef injected in the constructor 【发布时间】:2022-01-12 06:48:50 【问题描述】:我正在学习 jasmine 和 karma 的角度测试。我在我的项目中遇到了这个 showBanner() 方法,不知道如何进一步进行。这是一个服务方法,它使用给定的参数创建横幅组件,并在构造函数中注入 ComponentFactoryResolver 和 ApplicationRef。
我做了一些研究,但找不到与此相关的任何示例。如何模拟构造函数依赖项,特别是 ApplicationRef。我在某处读到它没有必要在测试平台的提供程序数组中模拟 ApplicationRef 但我不断收到此错误-> TypeError: Cannot read properties of undefined (reading 'instance') for the showBanner方法第 1 行,访问 appliationRef 的 components 属性。
这里是完整的服务方法
import ApplicationRef, ComponentFactoryResolver, Injectable, ViewContainerRef from "@angular/core";
import BannerComponent from "src/app/components/banner/banner.component";
import BannerSeverity from "src/app/utils/utils";
@Injectable(
providedIn: 'root'
)
export class BannerService
private resolver: ComponentFactoryResolver; // Reference to component factory resolver
banners : Array<any> = []; // Array to store all the banners
/**
* Constructor
*/
constructor(
resolver: ComponentFactoryResolver,
private applicationRef: ApplicationRef)
this.resolver = resolver;
/**
* Function called to show the banner with the specified configuration
*/
public showBanner(severity: BannerSeverity, message: string, dismissible?: boolean, appendTo?: ViewContainerRef, moreInfo?: string ): void
let globalViewContainerRef = this.applicationRef.components[0].instance.viewContainerRef;
let factory = this.resolver.resolveComponentFactory(BannerComponent);
let component = null;
if (appendTo)
component = appendTo.createComponent(factory);
else if (globalViewContainerRef)
component = globalViewContainerRef.createComponent(factory);
if (component)
let banner = component.instance;
banner.severity = BannerSeverity[severity];
banner.message = message;
banner.dismissible = dismissible;
banner.moreInfo = moreInfo;
banner.dismissed.subscribe(() =>
component.destroy();
);
this.banners.push(banner);
这是我的测试文件
import ApplicationRef, ComponentFactoryResolver from "@angular/core";
import fakeAsync, flush, TestBed from "@angular/core/testing";
import BannerSeverity from "src/app/utils/utils";
import getTypicalSetup from "src/testing/typical-setup";
import BannerService from "./banner.service";
/**
* Test cases for banner service.
*/
describe('BannerService', () =>
const mock = getTypicalSetup();
let bannerService: BannerService;
let BANNERS;
let componentFactoryResolverSpy;
/**
* Run some shared setup before each of the specs.
*/
beforeEach(fakeAsync(() =>
componentFactoryResolverSpy = jasmine.createSpyObj<ComponentFactoryResolver>('ComponentFactoryResolver', ['resolveComponentFactory']);
//Configure the test bed.
TestBed.configureTestingModule(
imports: [...mock.imports],
providers: [
...mock.providers,
BannerService,
provide: ComponentFactoryResolver, useValue: componentFactoryResolverSpy ,
],
);
bannerService = TestBed.inject(BannerService);
//Banners array with wasDismissed property.
BANNERS = [
wasDismissed: false ,
wasDismissed: false ,
];
));
/**
* Test to ensure the service is created.
*/
it('should be created', () =>
expect(bannerService).toBeDefined();
);
/**
* Test to ensure that the showBanner method creates a banner
* based on various parameters.
*/
describe('#showBanner', () =>
it('should create a banner with severity and message parameters passed', fakeAsync(() =>
//Arrange
const severity: BannerSeverity = BannerSeverity.critical;
const message: string = "Test Message";
//Act
bannerService.showBanner(severity, message);
flush();
//Assert
expect(bannerService.banners[0]).toBeDefined();
));
);
);
【问题讨论】:
【参考方案1】:您可以像 ComponentFactoryResolver
一样模拟它。
import ApplicationRef, ComponentFactoryResolver from "@angular/core";
import fakeAsync, flush, TestBed from "@angular/core/testing";
import BannerSeverity from "src/app/utils/utils";
import getTypicalSetup from "src/testing/typical-setup";
import BannerService from "./banner.service";
/**
* Test cases for banner service.
*/
describe('BannerService', () =>
const mock = getTypicalSetup();
let bannerService: BannerService;
let BANNERS;
let componentFactoryResolverSpy: jasmine.SpyObj<ComponentFactoryResolver>;
// add this line
let applicationRefSpy: jasmine.SpyObj<ApplicationRef>;
/**
* Run some shared setup before each of the specs.
*/
beforeEach(fakeAsync(() =>
componentFactoryResolverSpy = jasmine.createSpyObj<ComponentFactoryResolver>('ComponentFactoryResolver', ['resolveComponentFactory']);
// mock how you like
applicationRefSpy = jasmine.createSpyObj<ApplicationRef>('ApplicationRef', , components: [ instance: viewContainerRef: ] );
//Configure the test bed.
TestBed.configureTestingModule(
imports: [...mock.imports],
providers: [
...mock.providers,
BannerService,
provide: ComponentFactoryResolver, useValue: componentFactoryResolverSpy ,
// add mock
provide: ApplicationRef, useValue: applicationRefSpy ,
],
);
bannerService = TestBed.inject(BannerService);
//Banners array with wasDismissed property.
BANNERS = [
wasDismissed: false ,
wasDismissed: false ,
];
));
/**
* Test to ensure the service is created.
*/
it('should be created', () =>
expect(bannerService).toBeDefined();
);
/**
* Test to ensure that the showBanner method creates a banner
* based on various parameters.
*/
describe('#showBanner', () =>
it('should create a banner with severity and message parameters passed', fakeAsync(() =>
//Arrange
const severity: BannerSeverity = BannerSeverity.critical;
const message: string = "Test Message";
//Act
bannerService.showBanner(severity, message);
flush();
//Assert
expect(bannerService.banners[0]).toBeDefined();
));
);
);
查看此链接:https://***.com/a/64560773/7365461,了解如何使用 createSpyObj
模拟属性。
【讨论】:
以上是关于如何在 (jasmine + karma) 中为以下方法编写测试,该方法在构造函数中注入了 ComponentFactoryResolver 和 ApplicationRef的主要内容,如果未能解决你的问题,请参考以下文章
在Jasmine Unit Test中为PhantomJS配置浏览器语言
在Visual Studio 2013中使用Jasmine + Karma进行AngularJS测试