Angular中的单元测试点击事件

时间:2016-10-17 18:13:03

标签: angular jasmine

我正在尝试将单元测试添加到我的Angular 2应用中。在我的一个组件中,有一个带有(click)处理程序的按钮。当用户单击该按钮时,将调用一个在.ts类文件中定义的函数。该函数在console.log窗口中打印一条消息,说明该按钮已被按下。我目前的测试代码测试打印console.log消息:

describe('Component: ComponentToBeTested', () => {
    var component: ComponentToBeTested;

    beforeEach(() => {
        component = new ComponentToBeTested();
        spyOn(console, 'log');
    });

    it('should call onEditButtonClick() and print console.log', () => {
        component.onEditButtonClick();
        expect(console.log).toHaveBeenCalledWith('Edit button has been clicked!);
    });
});

但是,这只测试控制器类,而不是HTML。我并不想测试在调用onEditButtonClick时发生日志记录;我还想测试当用户单击组件的HTML文件中定义的编辑按钮时调用onEditButtonClick。我怎么能这样做?

5 个答案:

答案 0 :(得分:62)

  

我的目标是检查' onEditButtonClick'当用户单击编辑按钮而不是仅检查正在打印的console.log时,将调用此方法。

您需要先使用Angular TestBed设置测试。这样你就可以抓住按钮然后点击它。你将要做的是配置一个模块,就像你@NgModule一样,仅用于测试环境

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

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ ],
      declarations: [ TestComponent ],
      providers[  ]
    }).compileComponents().then(() => {
      fixture = TestBed.createComponent(TestComponent);
      component = fixture.componentInstance;
    });
  }));
});

然后你需要监视onEditButtonClick方法,点击按钮,然后检查方法是否被调用

it('should', async(() => {
  spyOn(component, 'onEditButtonClick');

  let button = fixture.debugElement.nativeElement.querySelector('button');
  button.click();

  fixture.whenStable().then(() => {
    expect(component.onEditButtonClick).toHaveBeenCalled();
  });
}));

这里我们需要运行async测试,因为按钮单击包含异步事件处理,需要通过调用fixture.whenStable()等待事件处理

另见:

答案 1 :(得分:33)

可以使用async提供的fakeAsync / '@angular/core/testing'函数测试事件,因为浏览器中的任何事件都是异步的并且被推送到事件循环/队列。

以下是使用fakeAsync测试点击事件的一个非常基本的示例。

fakeAsync函数通过在特殊fakeAsync测试区中运行测试体来启用线性编码样式。

这里我正在测试click事件调用的方法。

it('should', fakeAsync( () => {
    fixture.detectChanges();
    spyOn(componentInstance, 'method name'); //method attached to the click.
    let btn = fixture.debugElement.query(By.css('button'));
    btn.triggerEventHandler('click', null);
    tick(); // simulates the passage of time until all pending asynchronous activities finish
    fixture.detectChanges();
    expect(componentInstance.methodName).toHaveBeenCalled();
}));

以下是Angular docs所说的内容:

  

fakeAsync优于异步的主要优点是测试似乎是同步的。没有then(...)来破坏可见的控制流。承诺返回fixture.whenStable已消失,由tick()

取代      

的限制。例如,您无法在fakeAsync

内拨打XHR电话

答案 2 :(得分:1)

我正在使用 Angular 6 。我按照Mav55的回答进行了操作。但是我想确保fixture.detectChanges();是否真的有必要,所以我删除它仍然有效。然后我删除tick();以查看它是否有效并且确实有效。最后,我从fakeAsync()包装中删除了测试,并且惊讶,它有效。

所以我最终得到了这个:

it('should call onClick method', () => {
  const onClickMock = spyOn(component, 'onClick');
  fixture.debugElement.query(By.css('button')).triggerEventHandler('click', null);
  expect(onClickMock).toHaveBeenCalled();
});

它运作得很好。

答案 3 :(得分:0)

我遇到了类似的问题(详细解释如下),我使用jasmine-core: 2.52函数解决了它(在tick中)与原始setTimeout函数相同(或更大)的毫秒数1}}来电。

例如,如果我有setTimeout(() => {...}, 2500);(所以它会在2500毫秒后触发),我会调用tick(2500)来解决问题。

我在组件中的内容,作为对删除按钮的反应点击:

delete() {
    this.myService.delete(this.id)
      .subscribe(
        response => {
          this.message = 'Successfully deleted! Redirecting...';
          setTimeout(() => {
            this.router.navigate(['/home']);
          }, 2500); // I wait for 2.5 seconds before redirect
        });
  }

她是我的工作测试:

it('should delete the entity', fakeAsync(() => {
    component.id = 1; // preparations..
    component.getEntity(); // this one loads up the entity to my component
    tick(); // make sure that everything that is async is resolved/completed
    expect(myService.getMyThing).toHaveBeenCalledWith(1);
    // more expects here..
    fixture.detectChanges();
    tick();
    fixture.detectChanges();
    const deleteButton = fixture.debugElement.query(By.css('.btn-danger')).nativeElement;
    deleteButton.click(); // I've clicked the button, and now the delete function is called...

    tick(2501); // timeout for redirect is 2500 ms :)  <-- solution

    expect(myService.delete).toHaveBeenCalledWith(1);
    // more expects here..
  }));

P.S。有关fakeAsync和测试中的一般异步的详细解释,请访问:a video on Testing strategies with Angular 2 - Julie Ralph, starting from 8:10, lasting 4 minutes :)

答案 4 :(得分:-1)

首先要检查按钮调用事件,我们需要监视在单击按钮后将被调用的方法 所以我们的第一行是spyOn 间谍方法有两个参数 1)组件名称 2)被监视的方法,即:'onSubmit'记住不要使用'()'仅名称 那么我们需要使按钮的对象被点击 现在我们必须触发事件处理程序,在该事件处理程序上添加点击事件 那么我们希望我们的代码一次调用Submit方法

it('should call onSubmit method',() => {
    spyOn(component, 'onSubmit');
    let submitButton: DebugElement = 
    fixture.debugElement.query(By.css('button[type=submit]'));
    fixture.detectChanges();
    submitButton.triggerEventHandler('click',null);
    fixture.detectChanges();
    expect(component.onSubmit).toHaveBeenCalledTimes(1);
});