Angular中的单元测试点击事件

Aig*_*guo 53 jasmine typescript angular

我正在尝试将单元测试添加到我的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!);
    });
});
Run Code Online (Sandbox Code Playgroud)

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

Pau*_*tha 77

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

您需要首先使用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;
    });
  }));
});
Run Code Online (Sandbox Code Playgroud)

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

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

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

  fixture.whenStable().then(() => {
    expect(component.onEditButtonClick).toHaveBeenCalled();
  });
}));
Run Code Online (Sandbox Code Playgroud)

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

也可以看看:

  • 如果我们在 html 文件中有多个按钮怎么办?做类似的事情:fixture.debugElement.nativeElement.querySelector('button'); (2认同)
  • 在html文件中寻找'button',但是我们有两个以上的一个按钮?我应该如何引用第二个按钮的出现进行测试? (2认同)
  • 我得到了解决方案!button = fixture.debugElement.queryAll(By.css('button'); button1 = button [0]; (2认同)
  • 我花了一天的时间试图弄清楚为什么这对我不起作用才意识到我正在调用点击我的组件的元素而不是里面的div我实际上是在听点击. (2认同)

Mav*_*v55 36

事件可以使用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();
}));
Run Code Online (Sandbox Code Playgroud)

以下是Angular文档所说的内容:

fakeAsync优于异步的主要优点是测试似乎是同步的.没有then(...)破坏可见的控制流程.承诺回归fixture.whenStable已经消失,取而代之的是tick()

局限性.例如,您无法在a内进行XHR调用fakeAsync

  • 根据角度文档,@ AdamHughes fakeAsync更易于阅读和理解.但是你可以选择最适合自己的东西.使用aync或fakeAsync时,没有任何可接受的解决方案. (2认同)

Par*_*hal 5

我正在使用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();
});
Run Code Online (Sandbox Code Playgroud)

而且效果很好。