代码之家  ›  专栏  ›  技术社区  ›  Kolby

测试回调函数是在Angular项目中用Jasmine调用的

  •  8
  • Kolby  · 技术社区  · 6 年前

    我的Angular项目中有一个breadcrumbs组件,您在其中传入一个回调函数,单击breadcrumb时调用该函数。

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

    回调被添加到面包屑的 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 回复  |  直到 6 年前
        1
  •  1
  •   user4676340 user4676340    6 年前

    (我是根据我学到的知识来回答的,所以这可能是不对的,但我觉得这是合乎逻辑的,所以就在这里!)

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

    在您的例子中,您所做的是测试框架是否正在执行其工作(即发出事件)。

    我相信这不是您应该做的:这种测试将针对e2e测试,您应该从一端(前端)测试到另一端(后端)。

    这意味着如果我是你,我只会测试这个函数 callback

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

    这就是我的想法 要旨 是: 测试回调的作用,而不是它是否被调用 .

    我希望这有帮助。

        2
  •  0
  •   AleÅ¡ Doganoc    6 年前

    您使用createspy是正确的。在本例中,您还可以省略createspy中的名称。这在你的测试中不起作用吗?

    您可以更改的是不创建测试组件,而直接测试breadcrumbs组件。在这种情况下,我认为您不需要包装器组件,它只会使事情复杂化。然后测试将如下所示:

    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);
          });
        });
      }));
    });
    

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