【问题标题】:Angular 5: How do I deal with the dependencies of the dependencies of a component while unit testing?Angular 5:单元测试时如何处理组件的依赖关系?
【发布时间】:2018-09-23 02:25:41
【问题描述】:

我是 Angular 5 应用程序上下文中单元测试的新手。 现在,我正在尝试对一个基本组件进行单元测试。

该组件称为 CardComponent,在该组件的 HTML 中,我将其称为 CheckboxComponent。
这是 CardComponent 的 HTML:

<div>
    <p>Test</p>
    <jg-checkbox [label]="'Test label'"></jg-checkbox>
</div>

如您所见,没有什么复杂的事情发生。

但是,CheckboxComponent 确实注入了服务。为了这个问题,我就称它为TestService。

所以当我对 CardComponent 进行单元测试时,这里是我的测试平台:

TestBed.configureTestingModule({
    declarations: [
        CheckboxComponent
    ]
}).compileComponents();

然后我运行这个测试:

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

这只是通过 CLI 创建的默认测试。

但现在,它抱怨说没有 TestService 的提供者。我真的应该注入(和模拟/间谍)吗?

这似乎有点倒退,因为我只关心 CardComponent,我不应该关心 CheckboxComponent,对吧?这就是单元测试的重点。

否则,由于 Angular 具有分层组件,随着应用程序的增长,我可能不得不深入许多层次。

这不可能。

有人可以帮忙解决这个问题吗?感谢您的帮助!

【问题讨论】:

    标签: angular unit-testing


    【解决方案1】:

    是的,您需要创建一个模拟服务,涵盖您的组件在 ngOnInit() 函数中调用的每个服务函数。

    export class MockTestService {
        public myFunction() {
    
       }
    }
    
    ...
    describe('TheComponent', () => {
       const svc = new MockTestService();
    
    ...
    TestBed.configureTestingModule({
    declarations: [],
    providers: [{provide: TestService, useValue: svc}]
    }
    

    }).compileComponents();

    【讨论】:

    • 除非我做错了什么,否则它看起来不仅限于 ngOnInit()。只要它被注入到组件中,我就需要模拟。如果我有很大的组件层次结构,那可能会有大量的模拟。
    • 是的,您的应用程序组件将在您的应用程序使用的所有内容附近出现。因此,内部包含其他组件的组件更难测试。兄弟组件不需要这样做,只需要其他组件中的组件
    • 该死,太糟糕了。谢谢你告诉我!
    【解决方案2】:

    如果不需要在CardComponent中引用CheckboxComponent,有两种做法:

    • CheckboxComponent 可以被存根
    • NO_ERRORS_SCHEMA 可用于TestBed.configureTestingModule({})

    文档中有一个关于Nested component tests的部分

    还有一个关于Shallow component tests的答案

    存根

    card.component.spec.ts 中创建一个存根组件。

    @Component({selector: 'jg-checkbox', template: ''})
    class CheckboxStubComponent {}
    

    然后在TestBed.configureTestingModule({}) 中声明。

    TestBed.configureTestingModule({
      declarations: [
        CardComponent,
        CheckboxStubComponent
      ]
    })
    

    NO_ERRORS_SCHEMA

    NO_ERRORS_SCHEMA 可以用来代替存根。

    TestBed.configureTestingModule({
      declarations: [
        CardComponent
      ],
      schemas: [ NO_ERRORS_SCHEMA ]
    })
    

    NO_ERRORS_SCHEMA 告诉 Angular 编译器忽略无法识别的元素和属性。

    任何一种方法都是可以接受的。但是,文档中有关于过度使用 NO_ERRORS_SCHEMA 的警告。

    NO_ERRORS_SCHEMA 还可以防止编译器告诉您您无意中遗漏或拼写错误的缺失组件和属性。您可能会浪费数小时来追踪编译器会立即发现的幻像错误。

    它还提到存根有一个额外的优势。

    存根组件方法还有另一个优点。虽然本例中的存根是空的,但如果您的测试需要以某种方式与它们交互,您可以为它们提供精简的模板和类。

    它进一步展示了如何根据测试的需要同时使用这两种方法。

    【讨论】:

      【解决方案3】:

      虽然@josavish 的回答如果您只使用TestBed 是正确的,但NO-ERRORS-SCHEMA 会掩盖模板中的错误,并且手动创建的存根组件可能会很快失去同步,从而导致您的测试当他们应该失败时通过(再次掩盖真正的错误)!

      这正是我写shallow-render 的原因。使用Shallow,模拟复选框组件将是自动的。

      设置您的测试:

      const shallow: Shallow<CardComponent>;
      beforeEach(() => {
        shallow = new Shallow(CardComponent, TheModuleCardComponentIsDeclaredIn);
      });
      

      请注意,通过提供模块,您将自动能够使用模块中可用的组件(以及它的依赖项)。基本上,您将获得具有相同输入/输出属性的 jg-checkbox 模拟。

      然后,您可以使用以下规范验证组件的渲染:

      it('renders a checkbox with the correct label', async () => {
        const {findComponent} = await shallow.render();
        const checkbox = findComponent(CheckboxComponent);
      
        expect(checkbox.label).toBe('Test Label');
      });
      

      有很多示例规范 here 和完整的 readme

      希望这会有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-03
        • 1970-01-01
        • 2020-09-09
        • 2018-08-27
        • 1970-01-01
        • 2019-12-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多