简体   繁体   English

单元测试带有导入模块的angular2组件

[英]Unit Testing angular2 component with imported module

I am trying to write a test on a component which uses angular-material2, but when I add it to my testModule declarations I get: 我试图在使用angular-material2的组件上编写测试,但是当我将它添加到我的testModule声明时,我得到:

Error: Template parse errors:
    'md-card-title' is not a known element:
    1. If 'md-card-title' is an Angular component, then verify that it is part of this module.
    2. If 'md-card-title' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '@NgModule.schemas' of this component to suppress this message.

Adding MaterialModule to the declarations throws `Error: Unexpected module 'MaterialModule' declared by the module 将MaterialModule添加到声明中会抛出`错误:模块声明的意外模块'MaterialModule'

DynamicTestModule' in config/spec-bundle.js (line 24994) config / spec-bundle.js中的DynamicTestModule'(第24994行)

This is what my spec file looks like: 这是我的spec文件的样子:

  beforeEach(() => TestBed.configureTestingModule({
    declarations: [],
    providers: [
      { provide: DataService, useValue: mockDataService },
      { provide: ActivatedRoute, useClass: MockActivatedRoute },
      { provide: Router, useValue: mockRouter },
      CellViewComponent
    ]
  }));

adding CellViewComponent to the declarations array causes the error to throw. CellViewComponent添加到声明数组会导致错误抛出。

When you use the TestBed.configureTestingModule , you're create a module from scratch for the test environment. 当您使用TestBed.configureTestingModule ,您将从头开始为测试环境创建一个模块。 So what ever you would need in the real application for the CellViewComponent to work, you also need to configure it in the testing module. 因此,在CellViewComponent的实际应用程序中您需要的是,您还需要在测试模块中对其进行配置。

In your case, you're missing the Material card component. 在您的情况下,您错过了材料卡组件。 In the app you probably either imported the MaterialModule or the MdCardModule into your AppModule . 在应用程序中,您可能将MaterialModuleMdCardModule导入到AppModule So you need to do the same in the testing module 所以你需要在测试模块中做同样的事情

beforeEach(() => TestBed.configureTestingModule({
  imports: [ MaterialModule /* or MdCardModule */ ],
  declarations: [  CellViewComponent ],
  providers: [
    { provide: DataService, useValue: mockDataService },
    { provide: ActivatedRoute, useClass: MockActivatedRoute },
    { provide: Router, useValue: mockRouter },
  ]
}));

This is a real problem: you can mock everything but the imported component's selector. 这是一个真正的问题:您可以模拟除导入组件的选择器之外的所有内容。

There is an easy way. 有一个简单的方法。 It allows to avoid importing the modules, instead you can just disable this kind of errors. 它允许避免导入模块,而只是禁用这种错误。

Just add this to your module: 只需将其添加到您的模块:

import { NO_ERRORS_SCHEMA } from '@angular/core';

...

TestBed.configureTestingModule({
  schemas: [ NO_ERRORS_SCHEMA ],
  ...

Angular2 docs link Angular2文档链接

Yes, it won't help if you want to make integration (not isolated) tests, but it perfectly works for isolated ones. 是的,如果您想进行集成(非隔离)测试,它将无济于事,但它完全适用于孤立的测试。

Still even if you would decide to import a module I think it might be more correct to import the mock module with all implemented selectors instead. 即使你决定导入一个模块,我认为用所有实现的选择器导入mock模块可能更正确。

What I often do, when testing our Angular application components, is just import the parent module via reference. 在测试我们的Angular应用程序组件时,我经常做的只是通过引用导入父模块。 For most use cases, it is enough or close to enough and if you change the component, via adding new declarations or imports, then you do not need to worry about changing the test file, because the test file imports the parent module. 对于大多数用例,它足够或接近足够,如果您通过添加新的声明或导入来更改组件,则无需担心更改测试文件,因为测试文件会导入父模块。

I only ever change the module to import some external components for testing purposes, but this is rare. 我只是更改模块以导入一些外部组件用于测试目的,但这种情况很少见。

Regular test initialization pseudo code 定期测试初始化​​伪代码

beforeEach(() => TestBed.configureTestingModule({
    declarations: [
        ComponentA,
        ComponentB
    ],
    providers: [
        CellViewComponent
    ]
}));

let's say that this component is in a module. 假设这个组件在一个模块中。 I put the declarations object into a variable for use in ParentModule and Testing simultaneously. 我将声明对象放入一个变量中,以便在ParentModule和Testing中同时使用。

export var ParentModuleArgs = {
    declarations: [
        ComponentA,
        ComponentB
    ],
    providers: [
        CellViewComponent
    ]
  };

@NgModule(parentModuleArgs)
export class ParentModule {}

Then, instead of rewriting the whole Module array into the testing component and being very unDRY, I do. 然后,我没有将整个Module数组重写到测试组件中,而是非常unDRY。

beforeEach(() => TestBed.configureTestingModule(ParentModuleArgs));

And if I need to add something, then we can just add it before configuring the test bed 如果我需要添加一些东西,那么我们可以在配置测试台之前添加它

let moduleArgs: NgModule = ParentModuleArgs;
moduleArgs.providers.push({provide: APP_BASE_HREF, useValue: '/'});

beforeEach(() => TestBed.configureTestingModule(ParentModuleArgs));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM