26、端到端集成测试与页面对象的应用

端到端集成测试与页面对象的应用

在软件开发中,端到端测试是确保整个系统功能正常运行的重要环节。本文将详细介绍如何使用 Protractor 进行端到端测试,以及如何利用页面对象来优化测试代码。

1. 删除任务测试

在任务管理系统中,删除任务是一个常见的操作。为了测试删除任务的功能,我们需要点击任务表格中任务旁边的删除链接。由于可能存在多个删除链接,我们选择第二个链接(索引为 1),以确保删除第二个任务。

以下是具体的测试代码:

it('should successfully delete a task', function() {
    element.all(by.linkText('delete')).get(1).click();
    expect(element(by.id('message')).getText())
      .to.eventually.contain('task deleted');
    expect(element(by.id('tasks')).getText())
      .to.eventually.not.contain('Test Routes');
});

在这段代码中,我们使用了 Protractor 的 API 来定位和操作页面元素。 element.all(by.linkText('delete')).get(1) 用于选择第二个删除链接,然后调用 click() 方法进行点击操作。接着,我们使用 expect 语句来验证删除操作是否成功。

2. 集成测试问题与页面对象的引入

在编写集成测试时,我们可能会遇到一些问题,例如代码噪音、重复代码、页面实现的紧密耦合以及对 API 的紧密依赖。为了解决这些问题,我们可以使用页面对象。

页面对象是一种设计模式,它将页面的内容抽象成一个对象,测试代码可以通过这个对象来与页面进行交互,而不是直接操作浏览器对象和页面元素。这样可以减少代码噪音、重复代码,并且降低耦合度。

以下是一个使用页面对象的示例:

// 直接使用 Protractor API 的测试代码
it('should successfully add a task', function() {
    element(by.id('name')).sendKeys('Create Quality Code');
    element(by.id('date')).sendKeys('12/15/2016');
    element(by.id('submit')).click();
    expect(element(by.id('message')).getText())
      .to.eventually.contain('task added');
    expect(element(by.id('tasks')).getText())
      .to.eventually.contain('Create Quality Code');
});

// 使用页面对象的测试代码
it('should successfully add a task', function() {
    page.name = 'Create Quality Code';
    page.date = '12/15/2016';
    page.submit();
    eventually(page.message).contain('task added');
    eventually(page.tasksAsText).contain('Create Quality Code');
});

可以看到,使用页面对象的测试代码更加简洁、易读,并且减少了对 Protractor API 的直接依赖。

3. 创建页面对象

为了创建页面对象,我们需要两个文件:一个页面类和一个便利函数。

以下是 tasksj.html 页面的页面对象代码:

// tasksj-page.js
var fetchById = function(id) {
    return element(by.id(id));
};
var sendKey = function(element, text) {
    element.sendKeys(text);
};
var TasksJPage = function() {
    browser.get('/tasksj.html');
};
TasksJPage.prototype = {
    get tasksCount() { return
        fetchById('taskscount').getText(); },
    get tasksAsText() { return fetchById('tasks').getText(); },
    get message() { return fetchById('message').getText(); },
    deleteAt: function(index) {
        return element.all(by.linkText('delete')).get(index);
    },
    set name(text) { sendKey(fetchById('name'), text); },
    set date(text) { sendKey(fetchById('date'), text); },
    submit: function() { fetchById('submit').click(); }
};
module.exports = TasksJPage;

在这个页面对象中,我们定义了一些属性和方法,用于获取页面元素的文本内容、执行点击操作等。

4. 便利函数的使用

为了进一步减少测试代码的噪音,我们可以使用一个便利函数来简化 expect...eventually 的使用。

以下是便利函数的代码:

// eventually.js
var expect = require('chai').expect;
require('chai').use(require('chai-as-promised'));
module.exports = function(object) {
    return expect(object).to.be.eventually;
};

使用这个便利函数,我们可以将测试代码中的 expect...eventually 替换为 eventually ,使代码更加简洁。

5. 重写测试代码

使用页面对象和便利函数,我们可以重写之前的测试代码。以下是重写后的测试代码:

// tasksj-usepage-test.js
var eventually = require('./eventually');
var TasksPage = require('./tasksj-page');
describe('tasks ui test', function() {
    var page;
    beforeEach(function() {
        browser.ignoreSynchronization = true;
        page = new TasksPage();
    });
    afterEach(function() {
        browser.ignoreSynchronization = false;
    });
    it('page should show correct task count', function() {
        eventually(page.tasksCount).eql('4');
    });
    it('page should display tasks', function() {
        eventually(page.tasksAsText).contain('Test Models');
        eventually(page.tasksAsText).contain('Test UI');
    });
    it('should successfully add a task', function() {
        page.name = 'Create Quality Code';
        page.date = '12/15/2016';
        page.submit();
        eventually(page.message).contain('task added');
        eventually(page.tasksAsText).contain('Create Quality Code');
    });
    it('should successfully delete a task', function() {
        page.deleteAt(1).click();
        eventually(page.message).contain('task deleted');
        eventually(page.tasksAsText).not.contain('Test Routes');
    });
});

通过使用页面对象和便利函数,测试代码变得更加简洁、易读,并且减少了对 Protractor API 的直接依赖。

6. AngularJS 页面测试

Protractor 为 AngularJS 应用提供了一些特殊的功能。在测试 AngularJS 页面时,由于页面通常使用 ng-model ng-repeat 等指令,我们可以使用 Protractor 提供的便利函数来定位元素。

以下是一些常用的 Protractor 函数及其对应的 AngularJS 指令:
| 调用获取定位器 | 示例 | AngularJS 指令 |
| — | — | — |
| by.model(‘…’) | ng-model=‘…’ | ng-model |
| by.binding(‘controller.message’) | {{ controller.message }} | bindings |
| by.css(‘[ng-click=”…”]’) | ng-click=‘…’ | ng-click |
| by.repeater(‘task in…’) | ng-repeat=”task in…” | ng-repeat |
| by.repeater(‘task in…’).row(index) | ng-repeat=”task in…” | ng-repeat—a row |
| by.repeater(‘task in…’).column(‘task.name’) | ng-repeat=”…” | ng-repeat—columns |

为了测试 AngularJS 页面,我们需要创建一个专门的页面对象。以下是 tasksa.html 页面的页面对象代码:

// tasksa-page.js
var fetchByModel = function(model) {
    return element(by.model(model));
};
var fetchByBinding = function(binding) {
    return element(by.binding(binding));
};
var fetchByNgClick = function(clickFunction) {
    return element(by.css('[data-ng-click="' + clickFunction + '"]'));
};
var sendKey = function(element, text) {
    element.sendKeys(text);
};
var TasksAPage = function() {
    browser.get('/tasksa.html');
};
TasksAPage.prototype = {
    get tasksCount() {
        return
            fetchByBinding('controller.tasks.length').getText();
    },
    get tasksAsText() {
        return element.all(by.repeater('task in controller.tasks')
          .column('task.name')).getText();
    },
    get message() { return fetchByBinding('controller.message').getText(); },
    deleteAt: function(index) {
        return element(by.repeater('task in controller.tasks').row(index))
          .element(by.tagName('A'));
    },
    set name(text) { sendKey(fetchByModel('controller.newTask.name'), text); },
    set date(text) { sendKey(fetchByModel('controller.newTask.date'), text); },
    submit: function() {
        fetchByNgClick('controller.addTask();').click();
    },
    get submitDisabled() {
        return fetchByNgClick('controller.addTask();').getAttribute('disabled');
    }
};
module.exports = TasksAPage;

使用这个页面对象,我们可以编写测试代码来验证 tasksa.html 页面的功能。

7. Angular 2 页面测试

在测试 Angular 2 页面时,虽然 Protractor 对 Angular 2 的支持还在开发中,但我们仍然可以使用 Protractor 进行测试。

首先,我们需要在 protractor.conf.js 文件中添加一个新的配置项:

// protractor.conf.js
var app = require('./app');
var config = require('./config.json');
exports.config = {
    directConnect: true,
    baseUrl: 'http://localhost:' + (process.env.PORT || 3030),
    useAllAngular2AppRoots: true,
    framework: 'mocha',
    mochaOpts: {
        reporter: 'dot',
        timeout: 10000,
    },
    specs: ['test/integration/*.js'],
};

然后,我们需要创建一个专门的页面对象来测试 Angular 2 页面。以下是 tasksa.html 页面的 Angular 2 版本的页面对象代码:

// tasksa-page.js
var fetchModelById = function(modelId) {
    return element(by.id(modelId));
};
var fetchBindingById = function(bindingID) {
    return element(by.id(bindingID));
};
var fetchClickById = function(clickId) {
    return element(by.id(clickId));
};
var sendKey = function(element, text) {
    text.split('').forEach(function(ch) {
        element.sendKeys(ch);
    });
};
var TasksAPage = function() {
    browser.get('/');
};
TasksAPage.prototype = {
    get tasksCount() {
        return fetchBindingById('length').getText();
    },
    get tasksAsText() {
        return element(by.css('table')).getText();
    },
    get message() { return fetchBindingById('message').getText(); },
    deleteAt: function(index) {
        return element.all(by.css('table tr')).get(index)
          .element(by.tagName('A'));
    },
    set name(text) { sendKey(fetchModelById('name'), text); },
    set date(text) {
        var textSplit = text.split('/');
        var dateElement = fetchModelById('date');
        sendKey(dateElement, textSplit[0]);
        sendKey(dateElement, '/' + textSplit[1]);
        sendKey(dateElement, '/' + textSplit[2]);
    },
    submit: function() {
        fetchClickById('submit').click();
    },
    get submitDisabled() {
        return fetchClickById('submit').getAttribute('disabled');
    }
};
module.exports = TasksAPage;

最后,我们可以按照以下步骤进行 Angular 2 页面的集成测试:
1. 运行 npm install 安装依赖。
2. 运行 npm run-script update-driver 更新 WebDriver。
3. 启动数据库守护进程: mongod --dbpath db
4. 运行 npm run-script test-integration 启动 Protractor 进行测试。

通过以上步骤,我们可以使用 Protractor 对 Angular 2 页面进行有效的端到端测试。

综上所述,使用页面对象和 Protractor 可以帮助我们编写更加简洁、易读、可维护的端到端测试代码。无论是 jQuery 页面、AngularJS 页面还是 Angular 2 页面,我们都可以通过合理的设计和使用页面对象来提高测试效率和质量。

端到端集成测试与页面对象的应用

8. 测试代码示例及分析

为了更清晰地展示不同页面测试代码的差异和优势,我们将之前的测试代码进行对比分析。

以下是 tasksj.html 页面使用页面对象前后的测试代码对比:

// 直接使用 Protractor API 的测试代码
it('should successfully add a task', function() {
    element(by.id('name')).sendKeys('Create Quality Code');
    element(by.id('date')).sendKeys('12/15/2016');
    element(by.id('submit')).click();
    expect(element(by.id('message')).getText())
      .to.eventually.contain('task added');
    expect(element(by.id('tasks')).getText())
      .to.eventually.contain('Create Quality Code');
});

// 使用页面对象的测试代码
it('should successfully add a task', function() {
    page.name = 'Create Quality Code';
    page.date = '12/15/2016';
    page.submit();
    eventually(page.message).contain('task added');
    eventually(page.tasksAsText).contain('Create Quality Code');
});

从上述代码可以看出,使用页面对象后,测试代码更加简洁,减少了对 element by 等 Protractor API 的直接调用,降低了代码的耦合度。

接下来是 tasksa.html 页面的测试代码:

// tasksa-test.js
var eventually = require('./eventually');
var TasksPage = require('./tasksa-page');
describe('tasks ui test', function() {
    var page;
    beforeEach(function() {
        page = new TasksPage();
    });
    it('page should show correct task count', function() {
        eventually(page.tasksCount).eql('4');
    });
    it('page should display tasks', function() {
        eventually(page.tasksAsText).contain('Test Models');
        eventually(page.tasksAsText).contain('Test UI');
    });
    it('should successfully add a task', function() {
        page.name = 'Create Quality Code';
        page.date = '12/15/2016';
        page.submit();
        eventually(page.message).contain('task added');
        eventually(page.tasksAsText).contain('Create Quality Code');
    });
    it('should successfully delete a task', function() {
        page.deleteAt(1).click();
        eventually(page.message).contain('task deleted');
        eventually(page.tasksAsText).not.contain('Test Routes');
    });
    it('should disable submit button on page load', function() {
        eventually(page.submitDisabled).eql('true');
    });
    it('should enable submit button on data entry', function() {
        page.name = 'Create Quality Code';
        page.date = '12/15/2016';
        eventually(page.submitDisabled).not.eql('true');
    });
});

tasksa.html 页面的测试中,我们不仅验证了任务的添加和删除功能,还增加了对提交按钮状态的验证,确保在页面加载时按钮是禁用的,输入数据后按钮变为可用状态。

9. 测试流程总结

为了更直观地展示整个测试流程,我们可以使用 mermaid 流程图来表示:

graph LR
    A[开始] --> B[选择测试页面类型]
    B --> C{jQuery 页面}
    B --> D{AngularJS 页面}
    B --> E{Angular 2 页面}
    C --> F[创建 tasksj 页面对象]
    D --> G[创建 tasksa 页面对象(AngularJS 版本)]
    E --> H[创建 tasksa 页面对象(Angular 2 版本)]
    F --> I[编写测试代码并执行]
    G --> I
    H --> I
    I --> J[验证测试结果]
    J --> K[结束]

从流程图可以看出,无论选择哪种页面类型,都需要先创建对应的页面对象,然后编写测试代码并执行,最后验证测试结果。

10. 关键要点回顾

在进行端到端集成测试时,我们需要关注以下几个关键要点:
- 页面对象的使用 :通过创建页面对象,可以将页面的操作和元素定位封装起来,减少测试代码的噪音和重复,提高代码的可维护性。
- Protractor API 的选择 :根据页面的特点和使用的框架,选择合适的 Protractor API 来定位元素。对于 AngularJS 页面,可以使用 by.model by.binding 等特殊函数;对于普通页面,可以使用 by.id by.css 等函数。
- 测试流程的规范 :遵循一定的测试流程,包括创建页面对象、编写测试代码、执行测试和验证结果,确保测试的准确性和可靠性。

11. 常见问题及解决方案

在测试过程中,可能会遇到一些常见问题,以下是一些问题及对应的解决方案:
| 常见问题 | 解决方案 |
| — | — |
| 元素定位失败 | 检查元素的选择器是否正确,确保元素在页面上存在且可见。对于 AngularJS 页面,使用合适的 AngularJS 特定选择器。 |
| 测试结果不稳定 | 检查页面加载时间和异步操作,确保测试代码在页面完全加载后执行。可以使用 browser.wait 等函数来等待元素的出现。 |
| 代码耦合度高 | 使用页面对象将页面操作和元素定位封装起来,减少测试代码对页面实现的依赖。 |

12. 总结与展望

通过本文的介绍,我们了解了如何使用 Protractor 进行端到端集成测试,以及如何利用页面对象来优化测试代码。页面对象的使用可以使测试代码更加简洁、易读和可维护,同时降低了代码的耦合度。

在未来的测试工作中,我们可以进一步探索更多的测试技巧和工具,不断提高测试效率和质量。例如,可以结合自动化测试框架,实现更复杂的测试场景;可以使用数据驱动测试,提高测试的覆盖率。总之,持续学习和实践是提高测试能力的关键。

通过合理运用页面对象和 Protractor 进行端到端集成测试,我们能够更好地保证软件的质量和稳定性,为用户提供更优质的产品体验。

【Koopman】遍历论、动态模态分解和库普曼算子谱特性的计算研究(Matlab代码实现)内容概要:本文围绕【Koopman】遍历论、动态模态分解和库普曼算子谱特性的计算研究展开,重点介绍基于Matlab的代码实现方法。文章系统阐述了遍历理论的基本概念、动态模态分解(DMD)的数学原理及其库普曼算子谱特性之间的内在联系,展示了如何通过数值计算手段分析非线性动力系统的演化行为。文中提供了完整的Matlab代码示例,涵盖数据驱动的模态分解、谱分析及可视化过程,帮助读者理解并复现相关算法。同时,文档还列举了多个相关的科研方向和技术应用场景,体现出该方法在复杂系统建模分析中的广泛适用性。; 适合人群:具备一定动力系统、线性代数数值分析基础,熟悉Matlab编程,从事控制理论、流体力学、信号处理或数据驱动建模等领域研究的研究生、博士生及科研人员。; 使用场景及目标:①深入理解库普曼算子理论及其在非线性系统分析中的应用;②掌握动态模态分解(DMD)算法的实现优化;③应用于流体动力学、气候建模、生物系统、电力系统等领域的时空模态提取预测;④支撑高水平论文复现科研项目开发。; 阅读建议:建议读者结合Matlab代码逐段调试运行,对照理论推导加深理解;推荐参考文中提及的相关研究方向拓展应用场景;鼓励在实际数据上验证算法性能,并尝试改进扩展算法功能。
本系统采用微信小程序作为前端交互界面,结合Spring BootVue.js框架实现后端服务及管理后台的构建,形成一套完整的电子商务解决方案。该系统架构支持单一商户独立运营,亦兼容多商户入驻的平台模式,具备高度的灵活性扩展性。 在技术实现上,后端以Java语言为核心,依托Spring Boot框架提供稳定的业务逻辑处理数据接口服务;管理后台采用Vue.js进行开发,实现了直观高效的操作界面;前端微信小程序则为用户提供了便捷的移动端购物体验。整套系统各模块间紧密协作,功能链路完整闭环,已通过严格测试优化,符合商业应用的标准要求。 系统设计注重业务场景的全面覆盖,不仅包含商品展示、交易流程、订单处理等核心电商功能,还集成了会员管理、营销工具、数据统计等辅助模块,能够满足不同规模商户的日常运营需求。其多店铺支持机制允许平台方对入驻商户进行统一管理,同时保障各店铺在品牌展示、商品销售及客户服务方面的独立运作空间。 该解决方案强调代码结构的规范性可维护性,遵循企业级开发标准,确保了系统的长期稳定运行后续功能迭代的可行性。整体而言,这是一套技术选型成熟、架构清晰、功能完备且可直接投入商用的电商平台系统。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值