play+angularjs+karma unit test(单元测试)

戴瑞
2023-12-01

最近前后端代码写完了,研究下angularjs单元测试,网上找了好多资料,都是一知半解,很散,为了记录下痛苦的学习历程和为即将要学习的战友提供点帮助,决定写一下。

1.windows下安装nodeJS+NPM+Bower安装配置

2.安装和使用Karma-Jasmine

以上两个步骤去google,很多,这里不做介绍

注意:如果https下载不了,使用下面命令:

npm conf set registry http://registry.npmjs.org/

下面命令是清空缓存和安装npm和karma:
npm clean cache
npm install npm -g
npm install karma -g

3、安装好以上环境,在你的项目中新建karma.conf.js,可以使用karma init生成,然后再修改,以下是我的:

module.exports = function(config) {
  config.set({
    basePath: '..',//使用basePath,可以吧路径地址设置为在files和exclude属性中定义的相对路径,如果是相对地址,会被解析成相对于karma配置文件的位置
    frameworks: ['jasmine'],//使用哪个框架做测试,jasmine是默认的测试框架,不过也支持Mocha,QUnit和其他的
    logLevel: config.LOG_INFO,//输出日志的等级,config.LOG_DISABLE、config.LOG_ERROR、config.LOG_WARN、config.LOG_INFO、config.LOG_DEBUG
    files: [
        'public/javascripts/jquery/jquery-2.1.1.min.js',
        'public/javascripts/plugins/jquery-ui/jquery-ui.js',
        'public/javascripts/angular/angular.min.js',
        'public/javascripts/angular/angular-route.js',
        'public/javascripts/angular/angular-resource.js',
        'public/javascripts/angular/angular-mocks.js',
        'public/javascripts/angular/angular-animate.js',
        'public/javascripts/angular/angular-sanitize.min.js',
        'public/javascripts/angular-translate/angular-translate.min.js',
        'public/javascripts/ui-router/angular-ui-router.min.js',
        'public/javascripts/bootstrap/ui-bootstrap-tpls-0.12.0.min.js',
        'public/javascripts/angular/angular-touch.js',
        'public/javascripts/angular/angular-animate.js',
        'public/plugin/angular-ui-tree/dist/angular-ui-tree.js',
        'public/plugin/jsTree/jstree.min.js',
        'public/javascripts/plugins/oclazyload/dist/ocLazyLoad.js',
//        'public/javascripts/app.js',  复制一份到appTest,有一部分不需要加载
        'test/appTest.js',
//        'public/javascripts/config.js', 坑死了
        'public/javascripts/directives.js',
        'public/javascripts/controllers.js',
        'public/javascripts/services/formsService.js',
        'public/javascripts/controllers/formsCtrl.js',
        'public/javascripts/test.js',
        'test/ng/test_Spec.js',
    'test/ng/controllers/formsCtrl_Spec.js'
    ],//源文件和测试文件,因为我的app.js中,model需要很多插件,所以引入了很多指令js=
    exclude: [],//karma可以配出加载时不想引入的文件,如果你使用了requireJS,这个就很有用了
    //reporters: ['progress', 'coverage'],报表用的 没用到、
    port: 9876,//端口
    colors: true,//karma默认输出是有颜色的,可以关闭
    autoWatch: true,//设置成true会让karma在files中的文件发生变化时候执行已经配置的测试
    browsers: ['Chrome'],
    captureTimeOut: 60000,//浏览器加载时间查过captureTimeOut(默认60秒或者60000毫秒),karma会傻吊进程,再试一次,如果三次还是失败,karma就不在尝试启动浏览器了
    concurrency: Infinity
  })
}


4、加载angular.module时,karma.conf.js的files中要引入所有需要的js


5、接下来是jasmine关键的写法了

我的controller和service全写在一个js里,这里先说下单元测试的思路,由于之前写过一些回归测试,观念没转变过来,一直想着一个功能,从前端到接口再到数据库一下子可以全部测试,但是事实并非如此,测试controller,只是测试里边的一小个功能,例如一个排序的方法,我们只要固定一条数据,得到想要的结果就行了,测试service,这里说下$httpBackend,开始理解为用这个就是一个http请求,通过路由到接口再操作数据库,亲身经历过才知道,它只是一个模拟一个http请求,你定义好一个http请求的url和返回的状态、数据,如果service中确实调用了这个url,那么就会返回你定义好的状态和数据。最后httpBackend.flush();别忘了,非常重要,例如:

//controller代码
    $scope.getFormList = function(){
    	  var name = $scope.selName === undefined ? "" : ("&name=" + $scope.selName);
    	  var selStart = "?start=" + dbCur + "&limit=" + $scope.itemsPerPage; 
    	  formsService.formList(selStart+name).success(function(data) {
        	  $scope.gridOptions.data = data.data;
        	  $scope.totalCount = data.total;
              $scope.pageCount = Math.ceil($scope.totalCount / $scope.itemsPerPage) - 1;
          }).error(function(data) {
              $scope.errordata = data;
          });
      };

//service代码
    angular.module('inspinia').factory('formsService', ['$http', 'baseUrl',function($http, baseUrl){
	 	return {
        		formList: function(param) { //获取表单列表
           		var url = baseUrl + 'api/forms' + param;
            		return $http({
                	method: 'GET',
                	url: url          });
        	},      
	}]);

//测试代码
     beforeEach(inject(function (_formsService_, $httpBackend){
    	   formsService = _formsService_;
    	   httpBackend = $httpBackend;
           //下面这个语句:如果service调用了这个url,那么将会返回{"data":[{"_id":{"$oid":"57286b306d61a3fc61c58de5"},"name":"ggg"}],"total":1}
    	   httpBackend.whenGET( 'http://localhost:9000/api/forms?start=1&limit=100000')
    	   .respond(200, '{"data":[{"_id":{"$oid":"57286b306d61a3fc61c58de5"},"name":"ggg"}],"total":1}');
        }));

	it('should get a form from mongo', function(){
    	  expect(httpBackend).not.toEqual(null);
    	  $scope.getFormList();
    	  httpBackend.flush();
    	  expect($scope.totalCount).toEqual(1);
       }) 


研究了一天,转变了思路,觉得自己想复杂了,还是要多看官方文档,下面贴出整个测试代码:

 describe('inspinia controllers', function() {
	 
	 var scope,ctrl, formsService;
	 var http, baseUrl, httpBackend;
	 var $scope = {}
	 
     beforeEach(module('inspinia'));
     
     beforeEach(function() {
 	    module('inspinia', function($provide) {
 	      baseUrl = $provide.constant('baseUrl', 'http://localhost:9000/'); // <= mock your constant
 	    });
 	  });
     
     beforeEach(inject(function (_formsService_, $httpBackend){
    	 formsService = _formsService_;
    	 httpBackend = $httpBackend;
    	 httpBackend.whenGET( 'http://localhost:9000/api/forms?start=1&limit=100000')
    	 .respond(200, '{"data":[{"_id":{"$oid":"57286b306d61a3fc61c58de5"},"name":"ggg"}],"total":1}');
     }));
 
     beforeEach(inject(function ($rootScope, $controller) {
//         scope = $rootScope.$new();
         ctrl = $controller('formsCtrl', {$scope: $scope, formsService: formsService});
     }));
     
     it('begin init...', function(){
    	 $scope.init();
    	 expect($scope.itemsPerPage).toEqual(100000);
    	 expect($scope.currentPage).toEqual(0);
    	 expect($scope.totalCount).toEqual(0);
    	 expect($scope.selected).toEqual([]);
    	 expect($scope.add).toEqual({});
     })
     
     it('get sheetList', function(){
    	 $scope.getStyleSheetList();
    	 expect($scope.add.styleSheets).toEqual("传统表单");
     })
     
     it('click modify get data', function(){
    	 var kv = {"name":"1"};
    	 $scope.getUpd(kv);
    	 expect($scope.upd.name).toEqual("1");
     })
     
     it('should have an initial documentSaved state', function(){
         expect($scope.itemsPerPage).toEqual(100000);
         expect($scope.currentPage).toEqual(0);
         expect($scope.totalCount).toEqual(0);
     });
     
     it('click add button to clear data', function(){
    	 $scope.clearAddInfo(null);
    	 expect($scope.add.style).toEqual("申请表单");
    	 expect($scope.add.styleSheets).toEqual("传统表单");
     });
  
     it('should have a properly woking formsCtrl controller', function(){
    	 expect(ctrl).not.toEqual(null);
     })
     
     it('should have a properly working formsService service', function(){
    	 expect(formsService).not.toEqual(null);
     })
     
     it('should get a form from mongo', function(){
    	 expect(httpBackend).not.toEqual(null);
    	 $scope.getFormList();
    	 httpBackend.flush();
    	 expect($scope.totalCount).toEqual(1);
     })
     
   });

因为是初学angular,请勘误,接下来继续研究angularjs E2E,大家一起学习。



 类似资料: