site_prism中的Page Object

PageObject简介 PageObject是编写UI测试时的一种模式。简而言之,你可以将所有知道页面细节的部分放入到这个对象上,对于编写测试的人来说,一个PageObject代表了一个页面,或者页面上的一个区域(比如搜索框,搜索结果,侧边栏等都可能是一个独立的Object)。这样做的好处分为两个方面: 封装了所有的实现细节(内部的HTML是如何组织的) 对外的接口非常清晰,从而代码更加语义化 我们这里列举一个简单的例子来说明: 我们要测试的场景是:我们在一个搜索应用中,用户输入了ThoughtWorks,我们来判断搜索结果的第一页有10条结果。如果使用原生的capybara,代码大致会如下: visit '/search' fill_in 'Search', :with => 'ThoughtWorks' click_button '#search' expect(find('#result').find('.tips')).to have_content("10") 首先我们进入/search页面,然后在Search中输入了ThoughtWorks关键字,然后点击#search按钮,最后判断#result .tips下有10的字样。 如果使用PageObject,代码则会变成(这个是伪代码): search = SearchBox.new result = SearchResult.new search.type "ThoughtWorks" expect(result.count).to eq(10) site_prism 简介 site_prism是一个构建在capybara之上的用于建模Page Object的gem。使用site_prism可以很语义化的编写Page Object,可以使代码非常易读。 位于顶层的Page对象可以拥有多个Section对象,每个Section可以对应页面上的一些逻辑上的块,比如内容区域,边栏等。对于现在流行的SPA,我们只需要一个Page和若干个Section就足够了。 class MovingHome < SitePrism::Page set_url 'http://localhost:8100/bundles/moving-home' element :container, "#tmsCheckout" section :personal, PersonalSection, "#acc-personal" section :contact, ContactSection, "#acc-contact" end set_url方法制定了如何到达当前页,也是webdriver会实际发送请求的URL。页面本身上可以用element方法来声明一个元素,以及该元素对应的CSS选择器,这样就可以通过元素的名称来访问该选择器对应的HTML元素了。 比如上例中的container,我们在测试中就可以这样来访问它: @moving = MovingHome.new @moving.load @moving.container.should be_visible 而对应的section元素,则声明了一个块的名称,块的类和块的选择器。这样我们就可以通过名称来应用该块了: @moving.personal.name.set "Juntao" expect(@moving).to have_personal expect(@moving).to have_contact have_前缀加块的名称,用来判断该块是否可见(比如display: block)。...

January 2, 2015 · 2 min · 邱俊涛 | Juntao Qiu

为IE设置测试环境

IE下的测试 作为一个有追求的程序员,应该尽可能的远离Windows系统。不论从专业开发者的角度,还是仅仅作为最终用户从使用体验上来说,Windows都可以算是垃圾中的战斗机:没有shell、响应极慢(比如从开机到可用需要多久,再对比一下Mac下的体验)、大部分操作都强依赖于鼠标,没有对应的快捷键、各类病毒等等。 但是,最为一个职业的程序员,又很难绕开Windows这个猥琐而又事实上很现实的存在,毕竟Windows在非专业市场上的占有率还是不容小觑的。一般而言,开发人员可以很轻松的使用现代的操作系统,编辑器,开发工具完成实际的业务需求,这部分工作很可能占整个交付工作的40%,但是又不得不在多个浏览器(IE的各个版本)中花费另外的60%。 既然很难抛开,那么我们就需要想办法简化对其的使用,比如将Windows隔离为一个纯粹的测试环境(不安装任何其他的软件,并且一旦感染病毒之后可以快速恢复)。 将Windows安装到虚拟机中 使用工具将诸如下载镜像,安装系统,安装特定版本的IE等操作简化为一条命令 可以很容易的创建一个干净,纯粹,稳定的Windows环境 ievms正是这样一个工具,它提供安装了各种版本IE的Windows操作系统的镜像,支持IE6到IE11。默认的,用户可以安装从IE6到IE11的所有镜像,但是很可能你无须所有的环境,ievms也提供对应的参数来确保只下载某一个。 不过对于一个团队来讲,可以安装所有的镜像到团队的某台公共的机器上,供所有人来进行跨IE浏览器的各个版本的测试。 这些虚拟机镜像都是虚拟磁盘vmdk文件,因此你需要先安装VirtualBox。 安装ievms 安装ievms非常容易,只需要下载一个脚本即可: $ curl -s https://raw.githubusercontent.com/xdissent/ievms/master/ievms.sh -L github会将该请求重定向,所以加上-L参数来跳转到实际的地址。下载之后,执行该脚本: $ chmod +x ievms.sh $ ./ievms.sh 默认的ievms会下载所有的虚拟机镜像,可以通过参数IEVMS_VERSIONS来选择特定版本的虚拟机: $ ./ievms.sh IEVMS_VERSIONS="7 8 9" 当然,也可以将这些命令合并为一行命令: $ curl -s https://raw.githubusercontent.com/xdissent/ievms/master/ievms.sh -L | IEVMS_VERSIONS="7 8 9" bash 用法 安装之后,一个新的虚拟机会被添加到VirtualBox中,只需要启动这个虚拟机即可: 另外,在这个虚拟机中,可以很方便的连接到宿主机。比如在宿主机上的12306端口运行了某个Web应用,那么通过地址:http://10.0.2.2:12306 来访问这个应用。 注意: 由于是整个虚拟磁盘的形式发布,因此这些镜像的体积都非常大,所有的镜像安装之后,会占用37G的空间,对于任何一个开发机来说,这个尺寸过于庞大,但是对于整个团队来说,应该还是可以接受的。 官方给出的尺寸列表如下: $ du -ch * 11G IE10 - Win7-disk1.vmdk 11G IE11 - Win7-disk1.vmdk 1.5G IE6 - WinXP-disk1.vmdk 1.6G IE7 - WinXP-disk1.vmdk 1....

September 1, 2014 · 1 min · 邱俊涛 | Juntao Qiu

如何测试 Service - Angularjs

Service的典型示例 在AngularJS中,Service都是单例的实体,通常会将Service作为向后台交互的数据提供者,所有的需要数据的组件只需要依赖于这个Service即可。 var app = angular.module('MyApp', []); app.factory('SearchSettingService', ['$http', '$q', function($http, $q) { return { setting: function() { var deferred = $q.defer(); $http.get('/settings.json').success(function(result) { deferred.resolve(result); }).error(function(result) { deferred.reject("network error"); }); return deferred.promise; } }; }]); $httpBackend 测试的时候,我们不需要真实的发送HTTP请求来获取数据。如果可以只测试Service的逻辑,当发送请求时,我们将这个请求拦截下来,然后返回一个预定义好的数据即可: it('should have settings from http request', function() { var result; var expected = { "period": "day", "date": "Sat Dec 21 12:56:53 EST 2013", }; httpBackend.expectGET('/settings.json').respond(expected); var promise = settingService.setting(); promise.then(function(data) { result = data; }); httpBackend....

January 4, 2014 · 2 min · 邱俊涛 | Juntao Qiu

如何测试 Controller - Angularjs

AngularJS中的一个典型的Controller 在AngularJS中,Controller主要用于hold一些跟view的有关的状态,以及数据模型,比如界面上某些元素是否展示,以及展示那些内容等。通常来说,Controller会依赖与一个Service来提供数据: app.controller('EventController', ['$scope', 'EventService', function($scope, EventService) { EventService.getEvents().then(function(events) { $scope.events = events; }); }]); 而service本身则需要通过向后台服务发送请求来获取数据: app.factory('EventService', ['$http', '$q', function($http, $q) { return { getEvents: function() { var deferred = $q.defer(); $http.get('/events.json').success(function(result) { deferred.resolve(result); }).error(function(result) { deferred.reject(result); }); return deferred.promise; } }; }]); 通常的做法是返回一个promise对象,然后当数据准备完整之后,controller的then会被执行。 那么对于这种情况(在AngularJS中,算是一个非常典型的场景),我们如何进行单元测试呢? 测试依赖与Service的Controller 通常来讲,在单元级别的测试中,我们肯定不希望Service真正的发送请求,这样就变成了集成测试,而且前端的开发完全依赖与后台的开发进度/稳定程度等。 所以我们需要做一个假的Service,这个假的Service仅仅在测试中存在: var app = angular.module('MyApp'); describe("EventController", function() { var scope, q; var controllerFactory; var mockSerivce = {}; var events = ["Event1", "Event2", "Event3"]; beforeEach(function() { module("MyApp"); inject(function($rootScope, $controller, $q) { controllerFactory = $controller; scope = $rootScope....

December 28, 2013 · 1 min · 邱俊涛 | Juntao Qiu