在Angular项目中使用Jasmine调用了测试回调函数

时间:2018-05-29 21:02:48

标签: angular testing jasmine

我的Angular项目中有一个breadcrumbs组件,你传入一个回调函数,当点击面包屑时会调用它。

用户传入一个对象,该对象包含用于呈现面包屑的信息,以及单击面包屑时的回调。

回调被添加到面包屑的onclick事件中,并在用户点击一个时被调用。

<li *ngFor="let breadcrumb of breadcrumbs">
  <span (click)="breadcrumb.callback()">{{breadcrumb.title}}</span>
</li>

这是我尝试过的:

beforeEach(async(() => {
  TestBed.configureTestingModule({
    declarations: [BreadcrumbsTestComponent, Breadcrumbs]
  });
}));

it('should call given callback when breadcrumb is clicked', async(() => {
  const fixture = TestBed.createComponent(BreadcrumbComponent);
  fixture.detectChanges();

  const breadcrumbElements = fixture.nativeElement.querySelectorAll('.breadcrumb');

  breadcrumbElements.forEach(breadcrumb => {
    breadcrumb.click();
    fixture.whenStable().then(() => {
      expect(breadcrumb.callback).toHaveBeenCalled();
    });
  });
}));

const breadcrumbs = [
  {
    title: 'First Page',
    path: '/first',
    current: false,
    callback: jasmine.createSpy('callback')
  }, {
    title: 'Second Page',
    path: '/second',
    current: true,
    callback: jasmine.createSpy('callback')
  }
];

@Component({
  template: `<breadcrumbs [breadcrumbs]="breadcrumbs"></breadcrumbs>`
})
class BreadcrumbsTestComponent {
  breadcrumbs = breadcrumbs;
}

如何测试我的Jasmine测试中是否调用了回调?

感谢。

2 个答案:

答案 0 :(得分:1)

(我回答了我所学到的东西,所以它可能不对,但这对我来说是合乎逻辑的,所以在这里!)

进行单元测试时,您应该测试您编写的代码是否按预期工作。这样做是为了防止在进行修改时产生副作用。

在您的情况下,您正在做的是测试框架是否正在执行其工作(发生事件)。

我相信这不是你应该做的:这种测试将用于e2e测试,你应该从一端(前端)到另一端(后端)进行测试。

这意味着如果我是你,我只会测试面包屑的函数callback是否符合预期。

让我们假设它使面包屑闪烁:如果您测试面包屑是否闪烁,您将进行有用的测试。
因为如果有一天,你决定改变颜色而不是眨眼,那么你的测试会产生错误 同时,如果你想测试函数确实被调用,即使你彻底改变了回调的逻辑,测试也会通过。

我的底线是什么:测试回调的功能,而不是它的名字

我希望这会有所帮助。

答案 1 :(得分:0)

您使用create spy是正确的。在这种情况下,您还可以省略create spy中的名称。它在你的测试中不起作用吗?

您可以更改的是不创建测试组件并直接测试面包屑组件。在这种情况下,我认为你不需要一个包装器组件,它只会使事情复杂化。然后测试看起来像这样:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { BreadcrumbsComponent } from './breadcrumbs.component';
import { Breadcrumb } from '../breadcrumb/breadcrumb';
import { By } from '@angular/platform-browser';

describe('BreadcrumbsComponent', () => {
  let component: BreadcrumbsComponent;
  let fixture: ComponentFixture<BreadcrumbsComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ BreadcrumbsComponent ]
    })
    .compileComponents();
  }));

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

  it('should call given callback when breadcrumb is clicked', async(() => {
    const breadcrumbs: Breadcrumb[] = [
      {
        title: 'First Page',
        path: '/first',
        current: false,
        callback: jasmine.createSpy()
      }, {
        title: 'Second Page',
        path: '/second',
        current: true,
        callback: jasmine.createSpy()
      }
    ];
    component.breadcrumbs = breadcrumbs;
    fixture.detectChanges();
    const breadcrumbElements = fixture.debugElement.queryAll(By.css('span'));

    breadcrumbElements.forEach(breadcrumb => {
      breadcrumb.nativeElement.click();
    });

    fixture.whenStable().then(() => {
      breadcrumbs.forEach(breadcrumb => {
        expect(breadcrumb.callback).toHaveBeenCalledTimes(1);
      });
    });
  }));
});

我使用第一个框中的代码作为面包屑组件的代码,这就是为什么我在测试中查询span元素以单击它们的原因。