角度测试:TestBed不需要提供ApplicationRef

时间:2018-07-04 17:31:10

标签: angular testing

我正在遵循https://angular.io/guide/testing的官方“测试”指南,为应用程序编写测试。

在测试具有依赖项的服务时,我需要为这些依赖项提供模拟,但是有趣的是,这对于ApplicationRef似乎并不正确,我真的很想知道为什么。

该服务是这样的:

export class MyService {

    constructor(
        private dependentService: DependentService,
        private applicationRef:ApplicationRef
    ){}
    ...

以及相应的测试规范:

describe('MyService', () => {
    let dependentServiceSpy: jasmine.SpyObj<HttpClient>;

    beforeEach(() => {
        const dependentServiceSpy = jasmine.createSpyObj('DependentService', ['test']);

        TestBed.configureTestingModule({
            // Provide both the service-to-test and its (spy) dependency
            // why is 'ApplicationRef' not needed here?? 
            providers: [
                MyService,
                { provide: DependentService, useValue: dependentService_spy }
            ]
        });
    });
    ...   

});

由于在MyService构造函数中同时注入了'DependentService'和'ApplicationRef',因此我希望在TestBed的providers数组中都需要这两者。但是,虽然忽略了“ DependentService”,但会在测试中产生错误,而缺少的“ ApplicationRef”不会

对此有合理的解释吗?

3 个答案:

答案 0 :(得分:2)

每个使用TestBed的Angular测试配置都从以下初始化开始:

<script type="text/javascript">
importeReal = parseFloat({{$importe}});    
$(function() {  
    setTimeout(chequear, 1000);
});
function chequear() {
    $('input[data-denominacion]').each(function(index) {
        $(this).bind('change', function() {
            var valorInput = parseFloat($(this).val());
            var denominacion = parseFloat($(this).attr('data-denominacion'));
            if (/\D/.test(valorInput) || /\s/.test(valorInput)) {
                toastr.warning('Solo valores numericos, por favor'); 
                $(this).addClass('active');
            }
            if(/\d/.test(valorInput)) {    
                var denominacionXInputValue = valorInput * denominacion;
                importeReal = importeReal - denominacionXInputValue;
                console.log(importeReal);
                if(importeReal <= 0) {
                    toastr.warning('No puede poner mas denominaciones');
                } else {
                    toastr.info('Actualmente tienes sin ingresar' + importeReal);
                }
            }                 
            if(valorInput =='') {
                importeReal = importeReal + denominacionXInputValue;
                toastr.info('Actualmente tienes sin ingresar' + importeReal);
            } 
        });
    });        
}     
</script>

Angular测试环境将使用BrowserDynamicTestingModule构造注射器,因为它适用于普通Angular模块(另请参见https://blog.angularindepth.com/angular-dependency-injection-and-tree-shakeable-tokens-4588a8f70d5d)。

Angular合并getTestBed().initTestEnvironment( BrowserDynamicTestingModule, platformBrowserDynamicTesting() ); 包含的提供程序。该模块声明如下:

BrowserDynamicTestingModule

@NgModule({ exports: [BrowserTestingModule], providers: [ {provide: TestComponentRenderer, useClass: DOMTestComponentRenderer}, ] }) export class BrowserDynamicTestingModule { } 如下:

BrowserTestingModule

/\ || @NgModule({ exports: [BrowserModule], providers: [ {provide: APP_ID, useValue: 'a'}, ELEMENT_PROBE_PROVIDERS, {provide: NgZone, useFactory: createNgZone}, ] }) export class BrowserTestingModule { } 是:

BrowserModule

最后 /\ || @NgModule({providers: BROWSER_MODULE_PROVIDERS, exports: [CommonModule, ApplicationModule]}) export class BrowserModule { ... } 声明ApplicationModule

ApplicationRef

并且正如您所见, /\ || export const APPLICATION_MODULE_PROVIDERS: StaticProvider[] = [ { provide: ApplicationRef, useClass: ApplicationRef, deps: [NgZone, Console, Injector, ErrorHandler, ComponentFactoryResolver, ApplicationInitStatus] }, ... ]; @NgModule({providers: APPLICATION_MODULE_PROVIDERS}) export class ApplicationModule { // Inject ApplicationRef to make it eager... constructor(appRef: ApplicationRef) {} } 提供者也被热切实例化。

这样,这里就没有魔术了,Angular使用的算法与从用户定义的NgModules中解析提供程序的算法相同

答案 1 :(得分:1)

我不得不猜测,但是我认为:

每个组件都隐式包含更改检测。如果不是,则不会进行自动更改检测。 但是要直接在代码中使用此功能,必须在构造函数中显式“捕获”该服务。

现在,我们的TestBed将创建您在此处明确定义的服务。但是它还将创建所有这些内部需要的服务(例如ChangeDetection,请参见经典的“ fixture.detectChanges()”)。 因此,您不必显式创建它。

您提到的“ DependentService”不是内部Angular魔术的一部分,因此您必须在TestBed中明确命名它。

热烈的问候

答案 2 :(得分:1)

这可能是因为我们将ApplicationRef注入了constructor内而没有在任何地方提供它。这是正常的interface,而不是provider。我们仅提供测试providers内部的providers数组,而不提供我们注入的所有数组。 ChangeDetectorRef也是如此。我们永远不会在providers数组中提供该数组。