Модульное тестирование компонента angular 5 с @ViewChild

Я использую угловой 5.2.0. У меня есть дочерний компонент

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

@Component({
    template: `<div><\div>`
})
export class ChildComponent {

    public childMethod() {
        ...
    }
}

и родительский компонент, который обращается к дочернему через ViewChild

import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from 'child.component';

@Component({
    template: `<child-component #child><\child-component>`
})
export class ParentComponent {

    @ViewChild('child')
    public child: ChildComponent;

    public parentMethod() {
        this.child.childMethod();
    }
}

Мне нужен модульный тест, доказывающий, что вызов parentMethod вызывает вызов childMethod. У меня есть следующее:

import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ChildComponent } from './child.component';
import { ParentComponent } from './parent.component';

describe('ParentComponent', () => {

    let component: Parentcomponent;
    let fixture: ComponentFixture<Parentcomponent>;

    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [ ParentComponent, ChildComponent ],
            schemas: [ NO_ERRORS_SCHEMA ]
    }).compileComponents();
});

beforeEach(() => {
    fixture = TestBed.createComponent(TaskListPaginatorComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
});

    it('should invoke childMethod when parentMethod is invoked', () => {
        const childMethodSpy: jasmine.Spy = spyOn(component.child, 'childMethod');
        component.parentMethod();
        expect(childMethodSpy).toHaveBeenCalled();
    });

});

Однако это не работает, и я получаю Error: <spyOn> : could not find an object to spy upon for childMethod().

Более того, это не юнит-тест, потому что вместо мока я использую настоящий ChildComponent. Я попытался создать MockChildComponent и добавить его в declarations и export, но получил тот же результат. Любая помощь?

Я знаю, что есть похожие посты, но они для разных версий angular, и они не помогли.


person Jacopo Lanzoni    schedule 25.07.2018    source источник
comment
Вам следует избегать использования NO_ERRORS_SCHEMA. Если вы удалите его, он сообщит вам, что в вашем примере отсутствуют селекторы. С селекторами ваш пример работает. см. stackblitz.com/edit/angular-testing-ta7mfv Конечно, вы правы тем не менее, издевательство над ChildComponent - лучшее решение.   -  person Kim Kern    schedule 25.07.2018


Ответы (1)


Вы можете сделать что-то вроде этого.

Создайте объект-шпион для ChildComponent вот так.

const childComponent = jasmine.createSpyObj('ChildComponent', ['childMethod']);

Затем в тесте задайте для свойства childComponent созданный вами шпион.

  component.childComponent =  childComponent;

Ваш тестовый файл должен выглядеть так.

import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ChildComponent } from './child.component';
import { ParentComponent } from './parent.component';

describe('ParentComponent', () => {

    let component: ParentComponent;
    let fixture: ComponentFixture<ParentComponent>;

    const childComponent = jasmine.createSpyObj('ChildComponent', ['childMethod']);

    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [ ParentComponent, ChildComponent ],
            schemas: [ NO_ERRORS_SCHEMA ]
    }).compileComponents();
});

beforeEach(() => {
    fixture = TestBed.createComponent(ParentComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
});

    it('should invoke childMethod when parentMethod is invoked', () => {
        component.childComponent =  childComponent;
        component.parentMethod();
        expect(childComponent.childMethod).toHaveBeenCalled();
    });

});
person Anuradha Gunasekara    schedule 25.07.2018
comment
Спасибо, приятель, это сработало отлично! Я не думал об использовании createSpyObj, это было ключом! - person Jacopo Lanzoni; 25.07.2018
comment
Если этот ответ действительно помог вам, пожалуйста, отметьте его как правильный. Спасибо друг - person Anuradha Gunasekara; 25.07.2018
comment
На самом деле, с вашим предложением мне даже не нужно импортировать ChildComponent и добавлять его в объявления. Спасибо еще раз - person Jacopo Lanzoni; 25.07.2018
comment
Да . Помните, модульное тестирование — это тестирование одного модуля. Таким образом, вам не нужно тестировать или объявлять настоящий дочерний компонент. И поскольку вы не тестируете шаблон, вы можете просто создать шпион для дочернего компонента. - person Anuradha Gunasekara; 25.07.2018
comment
как вам это для @viewChildren? @Анурадха Гунасекара - person vidhya sagar; 21.01.2020
comment
Как сделать то же самое с помощью шутки ?? - person Soumya Gangamwar; 08.09.2020
comment
У меня есть ViewChild в компоненте, и я использую TestHostComponent, как бы вы издевались над этим дочерним элементом, чтобы он не попадал внутрь html-файла и не выдавал эту ошибку «zone-evergreen.js: 171 Uncaught TypeError: Не удается прочитать свойство «nativeElement» из неопределенного» - person Maddy; 05.03.2021