51Testing软件测试论坛

标题: 基于karma+jasmine的web前端自动化测试 [打印本页]

作者: 悠悠小仙仙    时间: 2018-1-16 15:32
标题: 基于karma+jasmine的web前端自动化测试
本帖最后由 悠悠小仙仙 于 2018-1-16 15:33 编辑

名词解释
Node.js是一个基于ChromeV8引擎的JavaScript运行环境。Node.js使用了一个事件驱动、非阻塞式I/O的模型,使其轻量又高效。Node.js的包管理器npm,是全球最大的开源库生态系统。
Karma是一个基于Node.js的JavaScript测试执行过程管理工具(TestRunner)。该工具可用于测试所有主流Web浏览器,也可集成到CI(Continuousintegration)工具,也可和其他代码编辑器一起使用。这个测试工具的一个强大特性就是,它可以监控(Watch)文件的变化,然后自行执行,通过console.log显示测试结果。
Jasmine是一个简易的JS单元测试框架。Jasmine不依赖于任何浏览器、DOM、或者是任何JavaScript而存在。它适用于所有网站、Node.js项目,或者是任何能够在JavaScript上面运行的程序。
环境安装
首先必须安装执行环境nodejs
安装浏览器,推荐chrome(用于运行监听程序,监听js文件变化,自动触发测试执行)
安装karma+jasmine
npminstallkarma-g
npminstallkarma-jasmine-g
npminstallkarma-chrome-launcher-g
npminstallkarma-cli-g
npminstallkarma-coverage-g
npminstallkarma-html-reporter-g
安装完成后执行karma-v,检查安装是否正常
工程配置
可以使用karmainit,自动生成配置文件,完成部分参数的设置,然后再手动修改。
当然最快的配置方法,复制下面的配置
  1. //Karmaconfiguration
  2.   //GeneratedonTueNov01201614:17:00GMT+0800(中国标准时间)
  3.   module.exports=function(config){
  4.   config.set({
  5.   //basepaththatwillbeusedtoresolveallpatterns(eg.files,exclude)
  6.   basePath:'',
  7.   //frameworkstouse
  8.   //availableframeworks:https://npmjs.org/browse/keyword/karma-adapter
  9.   frameworks:['jasmine'],
  10.   //listoffiles/patternstoloadinthebrowser
  11.   //需要加载入浏览器的js文件,包括基础的类库,被测试js文件和测试用例js文件
  12.   //如果需要测试angular代码,比如引入angular-mock.js,给angular代码进行mock。
  13.   //注意angular-mock的版本一定要和angular版本一致。可在cdn网站对应的angular版本列表中寻找
  14.   files:[
  15.   '../webapp/vender/jquery/jquery-1.10.2.min.js',
  16.   '../webapp/vender/angular/angular.min.js',
  17.   '../webapp/vender/angular/angular-ui-router.min.js',
  18.   'lib/angular-mocks.js',
  19.   '../webapp/common/*.js',
  20.   '../webapp/commont/template/*.html',
  21.   'tc/ut/**/*.js'
  22.   ],
  23.   //listoffilestoexclude
  24.   exclude:[
  25.   //'../webapp/vender/**/*.js'
  26.   ],
  27.   //testresultsreportertouse
  28.   //possiblevalues:'dots','progress'
  29.   //availablereporters:https://npmjs.org/browse/keyword/karma-reporter
  30.   //这里定义输出的报告
  31.   //html对应karma-html-reporter组件,输出测试用例执行报告
  32.   //coverage对应karma-coverage组件,输出测试用例执行报告
  33.   reporters:['progress','html','junit','coverage'],
  34.   junitReporter:{
  35.   //willberesolvedtobasePath(inthesamewayasfiles/excludepatterns)
  36.   outputFile:'report/ut/test-results.xml',
  37.   suite:'UT',
  38.   useBrowserName:false
  39.   },
  40.   htmlReporter:{
  41.   outputDir:'report/ut',
  42.   reportName:'result'//outputDir+reportName组成完整的输出报告格式,如没有定义,会自动生成浏览器+OS信息的文件夹,不方便读取报告
  43.   },
  44.   //定义需要统计覆盖率的文件
  45.   preprocessors:{
  46.   '../webapp/common/*.js':'coverage',
  47.   '../webapp/common/template/*.html':'ng-html2js'
  48.   },
  49.   coverageReporter:{
  50.   type:'html',//将覆盖率报告类型type设置为cobertura或者html
  51.   subdir:'coverage',//dir+subdir组成完整的输出报告格式,如没有定义,会自动生成浏览器+OS信息的文件夹,不方便读取报告
  52.   dir:'report/ut/'//代码覆盖率报告生成地址
  53.   },
  54.   //webserverport
  55.   port:9876,
  56.   //enable/disablecolorsintheoutput(reportersandlogs)
  57.   colors:true,
  58.   //leveloflogging
  59.   //possiblevalues:config.LOG_DISABLE||config.LOG_ERROR||config.LOG_WARN||config.LOG_INFO||config.LOG_DEBUG
  60.   logLevel:config.LOG_INFO,
  61.   //enable/disablewatchingfileandexecutingtestswheneveranyfilechanges
  62.   //karma自动自动监视被测试文件和测试用用例文件,如有修改,自动重新执行测试
  63.   autoWatch:true,
  64.   //ContinuousIntegrationmode
  65.   //iftrue,Karmacapturesbrowsers,runsthetestsandexits
  66.   //上一个参数为true,本参数为false,,则自动监视才生效。否则执行完测试用例后自动退出
  67.   singleRun:true,
  68.   //startthesebrowsers
  69.   //availablebrowserlaunchers:https://npmjs.org/browse/keyword/karma-launcher
  70.   //用来执行自动监听的浏览器,推荐chrome
  71.   browsers:['Chrome'],
  72.   //Concurrencylevel
  73.   //howmanybrowsershouldbestartedsimultaneous
  74.   concurrency:Infinity,
  75.   //自动将模板文件路径转换页面引入路径,以便注入用例中
  76.   ngHtml2JsPreprocessor:{
  77.   cacheIdFromPath:function(filepath){
  78.   varcacheId=filepath.substr(filepath.lastIndexOf('/webapp/')+7);
  79.   //console.log(cacheId);
  80.   returncacheId;
  81.   },
  82.   moduleName:'template'
  83.   }
  84.   })
  85.   }
  86.  保存配置文件到测试目录
  87.   测试用例编写
  88.   1、用例怎么写
  89.   describe("AsuiteofCommon/common.js",function(){
  90.   beforeAll(function(){
  91.   console.log('beforeAll');
  92.   });
  93.   describe("extendsofString",function(){
  94.   varexpected;
  95.   beforeEach(function(){
  96.   expected='abcd';
  97.   });
  98.   it("trim",function(){
  99.   expect(expected).toEqual(("abcd").trim());
  100.   });
  101.   it("ltrim",function(){
  102.   expect(expected).toEqual(("abcd").ltrim());
  103.   });
  104.   it("rtrim",function(){
  105.   expect(expected).toEqual(("abcd").rtrim());
  106.   });
  107.   });
  108.   });
  109.   上述例子中,
  110.   a.describe相当于一个测试套,可以嵌套。
  111.   b.it('tcname',function(){})是一个测试用例。
  112.   c.beforeAll和beforeEach是预置条件,前者一个测试套执行一次,后者每个测试用例执行一次。
  113.   d.当然还会有afterAll和afterEach
  114.   e.expect是断言
  115. 2、断言都有那些比较
  116.   Matcher实现了断言的比较操作,将Expectation传入的实际值和Matcher传入的期望值比较。任何Matcher都能通过在expect调用Matcher前加上not来实现一个否定的断言(expect(a).not().toBe(false);)。
  117.   常用的Matchers有:
  118.   toBe():相当于==比较。
  119.   toNotBe():相当于!=比较。
  120.   toBeDefined():检查变量或属性是否已声明且赋值。
  121.   toBeUndefined()
  122.   toBeNull():是否是null。
  123.   toBeTruthy():如果转换为布尔值,是否为true。
  124.   toBeFalsy()
  125.   toBeLessThan():数值比较,小于。
  126.   toBeGreaterThan():数值比较,大于。
  127.   toEqual():相当于==,注意与toBe()的区别。一个新建的Object不是(nottobe)另一个新建的Object,但是它们是相等(toequal)的。
  128.   expect({}).not().toBe({});
  129.   expect({}).toEqual({});
  130.   toNotEqual()
  131.   toContain():数组中是否包含元素(值)。只能用于数组,不能用于对象。
  132.   toBeCloseTo():数值比较时定义精度,先四舍五入后再比较。
  133.   toHaveBeenCalled()
  134.   toHaveBeenCalledWith()
  135.   toMatch():按正则表达式匹配。
  136.   toNotMatch()
  137.   toThrow():检验一个函数是否会抛出一个错误
  138.   3、angular代码怎么写
  139.   先看例子
  140.   describe('ApplyMainCtrl',function(){
  141.   var$scope,
  142.   $controller,
  143.   $httpBackend;
  144.   varMainCtrl;
  145.   beforeEach(module('applyApp'));
  146.   beforeEach(inject(function(_$controller_,$rootScope,_$httpBackend_){
  147.   $scope=$rootScope.$new();
  148.   $httpBackend=_$httpBackend_;
  149.   $controller=_$controller_;
  150.   $httpBackend.when('POST',/\/api\/wxcop\/common\/record.*/).respond({});
  151.   }));
  152.   it('Check$scopeassignments.',function(){
  153.   MainCtrl=$controller('MainController',{
  154.   $scope:$scope
  155.   });
  156.   $httpBackend.flush();
  157.   $scope.gotoApplyHome();
  158.   $scope.judgeLogin();
  159.   expect($scope.typeSelect).toEqual(["单行文本","多行文本","单选","多选"]);
  160.   expect($scope.getItemItems("1,2,3")).toEqual(["1","2","3"]);
  161.   });
  162.   });
  163.   注意,要测试angular必须引入angular-mock。
  164.   说明
  165.   beforeEach(module('applyApp'));引入module'applyApp'
  166.   beforeEach(inject(function($controller,$rootScope,$httpBackend)依赖注入和http测试打桩
  167.   $controller('MainController',)初始化controller
  168.   直接调用scope,然后执行断言
  169.   5、angular的相关特性如何测试
  170.   1、测试函数
  171.   a.被测试代码
  172.   $scope.functionTriger=false;
  173.   $scope.doTest=function(){
  174.   $scope.functionTriger=true;
  175.   }
  176.   b.测试用例
  177.   it('function',function(){
  178.   expect($scope.functionTriger).toBeFalsy();
  179.   $scope.doTest();
  180.   expect($scope.functionTriger).toBeTruthy();
  181.   });
复制代码






作者: 悠悠小仙仙    时间: 2018-1-16 15:34
  1. 2、测试监听
  2.   a.被测试代码
  3.   $scope.watchVar=false;
  4.   $scope.watchedTrigeIndex=0;
  5.   $scope.$watch('watchVar',function(){
  6.   $scope.watchedTrigeIndex++;
  7.   });
  8.   b.测试用例
  9.   it('watch',function(){
  10.   expect($scope.watchedTrigeIndex).toBe(0);
  11.   $scope.watchVar=true;
  12.   $scope.$digest();
  13.   expect($scope.watchedTrigeIndex).toBe(1);
  14.   $scope.watchVar=false;
  15.   $scope.$digest();
  16.   expect($scope.watchedTrigeIndex).toBe(2);
  17.   });
  18.   3、测试广播
  19.   a.被测试代码
  20.   $scope.isHaveTriger=false;
  21.   $scope.$on('ngRepeatFinished',function(){
  22.   $scope.isHaveTriger=true;
  23.   });
  24.   b.测试用例
  25.   it('broadcast',function(){
  26.   expect($scope.isHaveTriger).toBeFalsy();
  27.   $scope.$broadcast('ngRepeatFinished');
  28.   expect($scope.isHaveTriger).toBeTruthy();
  29.   });
  30.   4、测试路由切换
  31.   a.被测试代码
  32.   .config(['$stateProvider','$urlRouterProvider',function($stateProvider,$urlRouterProvider){
  33.   $urlRouterProvider.otherwise("/detail");
  34.   $stateProvider.state('detail',{
  35.   url:'/detail',
  36.   template:'<p></p>',
  37.   controller:'MainCtrl'
  38.   });
  39.   }])
  40.   b.测试用例
  41.   it('route',function(){
  42.   inject(function(_$injector_){
  43.   $state=_$injector_.get('$state');
  44.   });
  45.   varcurState=$state.get('detail');
  46.   expect(curState.name).toEqual('detail');
  47.   expect(curState.url).toEqual('/detail');
  48.   expect(curState.controller).toEqual('MainCtrl');
  49.   expect(curState.template).toEqual('<p></p>');
  50.   });
  51.   5、测试过滤器
  52.   a.被测试代码
  53.   .filter('myFilter',function(){
  54.   returnfunction(data){
  55.   returndata+'lzw';
  56.   }
  57.   })
  58.   b.测试用例
  59.   it('filter',function(){
  60.   inject(function(_$injector_){
  61.   $filter=_$injector_.get('$filter');
  62.   });
  63.   6、测试service
  64.   a.被测试代码
  65.   .service('foo',function(){
  66.   varthisIsPrivate="Private";
  67.   functiongetPrivate(){
  68.   returnthisIsPrivate;
  69.   }
  70.   return{
  71.   variable:"Thisispublic",
  72.   getPrivate:getPrivate
  73.   };
  74.   })
  75.   b.测试用例
  76.   it('service',function(){
  77.   varfoo;
  78.   inject(function(_foo_){
  79.   foo=_foo_;
  80.   });
  81.   expect(foo.variable).toBe('Thisispublic');
  82.   expect(foo.getPrivate()).toBe('Private');
  83.   });
  84.   7、测试指令
  85.   a.被测试代码
  86.   .directive('myDirective',function(){
  87.   return{
  88.   restrict:'A',
  89.   replace:true,
  90.   template:'<p>11</p>',
  91.   link:function(scope){}
  92.   };
  93.   })
  94.   .directive('dirButton',function(){
  95.   return{
  96.   template:'<button>Incrementvalue!</button>',
  97.   link:function(scope,elem){
  98.   elem.find('button').on('click',function(){
  99.   scope.value++;
  100.   });
  101.   }
  102.   };
  103.   })
  104.   .directive('dirScope',function(){
  105.   return{
  106.   scope:{
  107.   config:'=',
  108.   notify:'@',
  109.   onChange:'&'
  110.   },
  111.   link:function(scope){
  112.   }
  113.   };
  114.   })
  115.   b.测试用例
  116.   it('directive',function(){
  117.   varlink=$compile('<pmy-directive></p>');
  118.   varelement=link($scope);
  119.   expect($(element).html()).toBe('11');
  120.   });
  121.   it('buttondirective',function(){
  122.   vardirectiveElem=$compile('<buttondir-button></button>')($scope);
  123.   $scope.value=10;
  124.   varbutton=directiveElem.find('button');
  125.   button.triggerHandler('click');
  126.   $scope.$digest();
  127.   expect($scope.value).toEqual(11);
  128.   });
  129.   it('scopedirective',function(){
  130.   $scope.config={
  131.   prop:'value'
  132.   };
  133.   $scope.notify=true;
  134.   $scope.onChange=jasmine.createSpy('onChange');
  135.   vardirectiveElem=$compile(angular.element('<pdir-scopeconfig="config"notify="notify"on-change="onChange()"></p>'))($scope);
  136.   $scope.$digest();
  137.   varisolatedScope=directiveElem.isolateScope();
  138.   //test=
  139.   isolatedScope.config.prop="value2";
  140.   expect($scope.config.prop).toEqual('value2');
  141.   //test@
  142.   isolatedScope.notify=false;
  143.   expect($scope.notify).toEqual(true);
  144.   //test&
  145.   expect(typeof(isolatedScope.onChange)).toEqual('function');
  146.   isolatedScope.onChange();
  147.   expect($scope.onChange).toHaveBeenCalled();
  148.   //调用指令的父controller。
  149.   directiveElem.scope().doFunction();
  150.   });
  151.   关于mock
  152.   $httpBackend
  153.   $httpBackend对于代码中的http请求进行mock。常用方法:
  154.   $httpBackend.when(method,url,[data],[headers]);
  155.   $httpBackend.expect(method,url,[data],[headers]);
  156.   when和expect都有对应的快捷方法:
  157.   whenGET(url,[headers]);
  158.   whenHEAD(url,[headers]);
  159.   whenDELETE(url,[headers]);
  160.   whenPOST(url,[data],[headers]);
  161.   whenPUT(url,[data],[headers]);
  162.   whenJSONP(url);
  163.   expectGET(url,[headers]);
  164.   expectHEAD(url,[headers]);
  165.   expectDELETE(url,[headers]);
  166.   expectPOST(url,[data],[headers]);
  167.   expectPUT(url,[data],[headers]);
  168.   expectPATCH(url,[data],[headers]);
  169.   expectJSONP(url);
  170.   url支持正则,比如:
  171.   $httpBackend.when('POST',/\/api\/wxcop\/common\/record.*/).respond({});
  172.   注意:
  173.   $httpBackend.when与$httpBackend.expect的区别在于:$httpBackend.expect的伪后台只能被调用一次(调用一次后会被清除),第二次调用就会报错,而且$httpBackend.resetExpectations可以移除所有的expect而对when没有影响。
  174.   常见异常处理
  175.   Argument'MainCtrl'isnotafunction,gotundefined
  176.   无法找到MainCtrl。可能原因:controller定义错误,app注入失败。
  177.   Disconnected,becausenomessagein10000ms.
  178.   ajax请求超时。原因:$httpBackend.flush();要放在ajax发起请求后执行。
  179.   指令采用templateUrl方式加载模板失败
  180.   可采用karma-ng-html2js-preprocessor插件自动注入。也可以采用$templateCache注入。注意,这两种方式都不支持模糊匹配
复制代码

作者: 梦想家    时间: 2018-5-14 17:28





欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2