Angular端到端(E2E)测试新手求助:首次编写测试需指导
嘿,作为刚接触Angular和E2E测试的新手,第一次写测试确实会有点无从下手,我结合你给出的组件代码,给你梳理一套实用的E2E测试方案,帮你快速上手~
针对你的Listing组件的E2E测试指导
首先,核心思路要明确:E2E测试是模拟真实用户的操作流程,验证组件在不同场景下的行为是否符合预期。结合你的组件(包含异步数据加载、搜索过滤、选中状态、加载/空状态),我们可以覆盖以下关键测试场景:
第一步:给HTML添加测试友好的标识
为了让测试更稳定(避免因为CSS类或文本变化导致测试失败),建议给关键元素加上data-testid属性,修改后的代码片段如下:
<md-list> <div *ngIf="items | async as items; else loading"> <ng-container *ngIf="items.length; else noItems"> <div class="item-row" *ngFor="let item of items | search:'LoanNumber,Borrower_LastName,Borrower_FirstName':searchTerm" [class.selected]="selectedItemId === item.ORDER_ID" data-testid="item-row" [attr.data-order-id]="item.ORDER_ID" > <list-item [item]="item" data-testid="list-item"></list-item> </div> </ng-container> <ng-template #noItems> <p data-testid="no-items-message">没有找到任何项目</p> </ng-template> </div> <ng-template #loading> <md-spinner data-testid="loading-indicator"></md-spinner> </ng-template> </md-list> <!-- 假设你的搜索输入框结构如下,同样加上测试标识 --> <input type="text" [(ngModel)]="searchTerm" data-testid="search-input" placeholder="搜索贷款号或借款人">
第二步:编写Cypress测试用例(Angular CLI默认推荐)
现在Angular主流的E2E工具是Cypress,下面是针对你的组件的完整测试代码,每个用例对应一个真实场景:
describe('Listing Component E2E Tests', () => { beforeEach(() => { // 访问组件所在的页面,替换成你的实际路由 cy.visit('/listings'); }); // 测试加载状态流程 it('显示加载指示器直到异步数据加载完成', () => { // 初始状态验证加载指示器可见 cy.get('[data-testid="loading-indicator"]').should('be.visible'); // 拦截后端API请求,模拟返回测试数据(替换成你的实际API地址) cy.intercept('GET', '/api/items', { delay: 1000, // 模拟网络延迟,更贴近真实场景 body: [ { ORDER_ID: 1, LoanNumber: 'LN-123', Borrower_LastName: 'Smith', Borrower_FirstName: 'John' }, { ORDER_ID: 2, LoanNumber: 'LN-456', Borrower_LastName: 'Doe', Borrower_FirstName: 'Jane' } ] }).as('getItems'); // 等待请求完成,验证加载指示器消失,列表项正确渲染 cy.wait('@getItems'); cy.get('[data-testid="loading-indicator"]').should('not.exist'); cy.get('[data-testid="item-row"]').should('have.length', 2); }); // 测试无数据场景 it('当没有数据时显示空状态提示', () => { // 拦截API返回空数组 cy.intercept('GET', '/api/items', []).as('getEmptyItems'); cy.wait('@getEmptyItems'); // 验证空状态提示可见,列表项不存在 cy.get('[data-testid="no-items-message"]').should('be.visible').and('contain', '没有找到任何项目'); cy.get('[data-testid="item-row"]').should('not.exist'); }); // 测试搜索过滤功能 it('搜索关键词能正确过滤列表项', () => { // 加载测试数据 cy.intercept('GET', '/api/items', [ { ORDER_ID: 1, LoanNumber: 'LN-123', Borrower_LastName: 'Smith', Borrower_FirstName: 'John' }, { ORDER_ID: 2, LoanNumber: 'LN-456', Borrower_LastName: 'Doe', Borrower_FirstName: 'Jane' } ]).as('getItems'); cy.wait('@getItems'); // 搜索"John",验证只有匹配的项显示 cy.get('[data-testid="search-input"]').type('John'); cy.get('[data-testid="item-row"]').should('have.length', 1); cy.get('[data-testid="item-row"][data-order-id="1"]').should('be.visible'); // 搜索"LN-456",验证只有对应的项显示 cy.get('[data-testid="search-input"]').clear().type('LN-456'); cy.get('[data-testid="item-row"]').should('have.length', 1); cy.get('[data-testid="item-row"][data-order-id="2"]').should('be.visible'); // 搜索不存在的关键词,验证显示空状态 cy.get('[data-testid="search-input"]').clear().type('NonExistent'); cy.get('[data-testid="no-items-message"]').should('be.visible'); }); // 测试选中状态 it('点击列表项后会添加选中样式', () => { // 加载单条测试数据 cy.intercept('GET', '/api/items', [ { ORDER_ID: 1, LoanNumber: 'LN-123', Borrower_LastName: 'Smith', Borrower_FirstName: 'John' } ]).as('getItems'); cy.wait('@getItems'); // 点击列表项,验证selected类被添加 const itemRow = cy.get('[data-testid="item-row"]'); itemRow.click(); itemRow.should('have.class', 'selected'); }); });
新手必备小贴士
- 定位元素的最佳实践:尽量用
data-testid而不是CSS类或文本内容,因为前者不会因为UI样式或文案修改而失效 - 模拟真实场景:测试时要模拟用户的真实操作流程(比如先加载页面,再输入搜索词,再点击),不要直接操作组件内部变量
- 运行测试:确保Angular应用处于运行状态,或者用
ng e2e命令自动启动应用并运行测试 - 如果用Protractor:思路和上面一致,只是语法不同,比如用
element(by.css('[data-testid="search-input"]')).sendKeys('John');来模拟输入
内容的提问来源于stack exchange,提问作者yugaanks
相关产品推荐
相关产品推荐

