【发布时间】:2020-06-12 15:31:48
【问题描述】:
我有一个单元测试,我想测试一个函数是否在单击按钮时被调用。但我不断收到此错误:Expected spy archive to have been called.,我无法弄清楚为什么它不起作用。
我有什么遗漏或做错了吗?有关上下文,请参见下面的代码。
这是我的测试
it('should call archive function on button click', async(() => {
spyOn(component, 'archive');
fixture.detectChanges();
component.project = rh.getProjects(1)[0];
dh.clickButton('Archive');
fixture.detectChanges();
expect(component.archive).toHaveBeenCalled();
}));
这是 dh aka DOMHelper
clickButton(buttonText: string) {
this.findAll('button').forEach(button => {
const buttonElement: HTMLButtonElement = button.nativeElement;
if (buttonElement.textContent === buttonText) {
buttonElement.click();
}
});
}
findAll(tagName: string) {
return this.fixture.debugElement
.queryAll(By.css(tagName));
}
这是html
<td data-label="Title">{{ project.title }}</td>
<td data-label="Owner">{{ getOwnerName(project.owner) }}</td>
<td data-label="Actions">
<button class="btn btn-primary" (click)="dashboard">Dashboard</button>
<button *ngIf="authService.firebaseAuth.auth.currentUser.uid == project.owner" class="btn btn-primary" (click)="archive">Archive</button>
</td>
这是 component.ts 文件
import { Component, OnInit, Input } from '@angular/core';
import { Project } from 'src/app/models/project';
import { AuthService } from 'src/app/services/auth.service';
import { ProjectService } from 'src/app/services/project.service';
import { Router } from '@angular/router';
@Component({
selector: 'tr[app-joined-project-item]',
templateUrl: './joined-project-item.component.html',
styleUrls: ['./joined-project-item.component.css'],
})
export class JoinedProjectItemComponent implements OnInit {
@Input() public project: Project;
constructor(public authService: AuthService, public projectService: ProjectService, private router: Router) {}
ngOnInit(): void {
}
archive() {
this.projectService.updateArchivedStatusProject(this.project);
}
dashboard() {
this.router.navigate(['/projects/' + this.project.id + '/dashboard'])
}
getOwnerName(userId: string) {
return Object.values(this.project.members).find((member: any) => member['userId'] === userId)['name'];
}
}
更新
当我在检查服务函数是否被调用的地方进行测试时,我收到以下错误:Expected spy updateArchivedStatusProject to have been called with: *Project Object* but it was never called.
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [JoinedProjectItemComponent],
providers: [
{ provide: ProjectService, useClass: MockProjectService },
{ provide: AuthService, useClass: MockAuthService },
{ provide: Router, useValue: routerSpy }
]
}).compileComponents();
}));
it('should call archive function on button click', async(() => {
spy = spyOn(TestBed.get(ProjectService), 'updateArchivedStatusProject');
fixture.detectChanges();
component.project = rh.getProjects(1)[0];
dh.clickButton('Archive');
fixture.detectChanges();
expect(spy).toHaveBeenCalledWith(rh.projects[0]);
}));
【问题讨论】:
-
我不建议通过监视组件的方法来测试组件。使用服务的测试替身,并断言其
updateArchivedStatusProject方法被正确的项目调用。通常,您应该通过公共接口(对于 Angular 组件:@Input/@Outputs、DOM 以及与注入的协作者的交互)测试行为,而不是实现。 -
我添加了问题的更新。当我测试是否调用了模拟的服务函数时,我得到了它从未被调用过的错误
-
如果您尝试单击的按钮不在 DOM 中,
DOMHelper中的clickButton方法不会引发错误。因为上面有一个*ngIf,所以我猜它不是。如果从findAll返回的数组为空,请尝试记录找到的按钮和/或抛出错误。这将有助于调试失败的测试。 -
该按钮在该方法中被找到,因为如果我在
if (buttonElement.textContent === buttonText)内登录,我会得到按钮<button _ngcontent-a-c36="" class="btn btn-primary">Archive</button> -
我认为这里的问题有所不同(见答案)。但是我认为在缺少元素的情况下在该方法中抛出错误将在将来对您有所帮助。
标签: angular typescript karma-jasmine