【问题标题】:Unit Test large number of injected services using Jasmine使用 Jasmine 对大量注入服务进行单元测试
【发布时间】:2016-04-11 12:28:24
【问题描述】:

我对使用 Jasmine 进行 AngularJs 单元测试非常陌生。所以你能告诉我如何使用 Jasmine 测试下面提到的控制器和 countyService.getAllCountiesAsync() 方法。提前致谢。

注意:下面的控制器有超过 50 个注入服务(我在下面展示了几个)。所以我不知道哪种方法也适合模拟这些服务?

控制器:

(function () {
    appModule.controller('myController', [
        '$scope', '$modalInstance', 'abp.services.app.property', 'abp.services.app.county', 'abp.services.app.propertyClass', 'abp.services.app.schoolDistrict'
        function ($scope, $modalInstance, propertyService, countyService, propertyClassService, schoolDistrictService) {

   vm.getAllCounties = function () {
                countyService.getAllCountiesAsync().success(function (result) {
                    vm.counties = result.items;
                });
            };

            vm.getAllCounties();

} ]);
})();

WebApi 方法:

  public async Task<ListResultOutput<CountyListDto>> GetAllCountiesAsync()
        {
            var counties = await _countyRepository
                .GetAllListAsync();

            return new ListResultOutput<CountyListDto>(counties.OrderBy(o => o.Name).MapTo<List<CountyListDto>>());
        }

【问题讨论】:

    标签: angularjs unit-testing jasmine


    【解决方案1】:

    我假设您为所有服务创建了 Angular 服务,并且您的应用程序正在运行。然后,您可以将它们注入到您的测试中:

    describe('service tests', function () {
    
    var $compile, $rootScope, propertyService, countyService, propertyClassService, schoolDistrictService;
      beforeEach(module('your-app-name'));
      beforeEach(inject(function(_$compile_, _$rootScope_, _propertyService_, _countyService_, _propertyClassService_, _schoolDistrictService_) {
        $compile = _$compile_;
        $rootScope = _$rootScope_;
        propertyService = _propertyService_;
        countyService = _countyService_;
        propertyClassService = _propertyClassService_;
        schoolDistrictService = _schoolDistrictService_;
      }));
    
      it('should test something', function() {
        expect(propertyService).toBeDefined();
        expect(countyService).toBeDefined();
        expect(propertyClassService).toBeDefined();
        expect(schoolDistrictService).toBeDefined();
      });
    
    });
    

    更新

    我不小心在上面的答案中发布了我的解决方案,所以现在更正了。您可以使用 $controller 创建控制器并传入范围对象。您还可以传入任何其他依赖项。然后在服务上创建一个间谍,一旦它被调用,调用一个不同的函数来解析一个带有模拟数据的承诺:

    describe('service tests', function () {
    
    var $compile, $rootScope, scope, vm, propertyService, countyService, propertyClassService, schoolDistrictService;
      beforeEach(module('your-app-name'));
      beforeEach(inject(function(_$compile_, _$rootScope_, $controller, _propertyService_, _countyService_, _propertyClassService_, _schoolDistrictService_) {
        $compile = _$compile_;
        $rootScope = _$rootScope_;
        scope = $rootScope.$new();
        propertyService = _propertyService_;
        countyService = _countyService_;
        propertyClassService = _propertyClassService_;
        schoolDistrictService = _schoolDistrictService_;
    
        // Create the controller, and pass in the scope with possible variables that you want to mock.
        vm = $controller('myController', {'$scope': scope})
    
        //Create a spy on your getAllCountiesAsync function and make it return a mock promise with mock data.
        spyOn(countyService, "getAllCountiesAsync").and.callFake(function() {
            var deferred = $q.defer();
            deferred.resolve({data: [{id:0}]});
            return deferred.promise;
        });
      }));
    
      it('can do remote call', inject(function() {
    
        //Arrange
        result = [{id:0}];
    
        // Act
        vm.getAllCounties();
    
        //I think that you also have to do this, but I am not a 100% sure.
        scope.$apply();
    
        // Assert
        expect(vm.counties).toBe(result); //assert to whatever is resolved in the spyOn function
    
      });   
    
    });
    }
    

    【讨论】:

    • 你能告诉我如何测试这个方法vm.getAllCounties吗?谢谢。
    • 您应该考虑为您的服务创建一个间谍并模拟答案。示例:stackoverflow.com/questions/23705051/….
    • 感谢您的链接。我会阅读它。但我对这个主题很陌生。你上面的解释对我来说非常清楚。所以当你有时间时,你也可以测试vm.getAllCounties 函数吗?然后我可以通过我的例子本身来理解这个概念。谢谢。
    • 抱歉,我看不到上述帖子的任何更新? vm.getAllCounties 方法的测试用例在哪里?谢谢。
    • 我一定是关闭笔记本电脑太快了,因为我有点急于去参加一个会议。将在今天晚些时候上传,抱歉。
    【解决方案2】:

    你应该为服务和控制器编写测试用例。

    对于服务“Daan van Hulst”已经给出了答案,对于控制器,请参见以下代码:

    describe('service tests', function () {
    
    var $compile,$controller,myController, $rootScope, propertyService, countyService, propertyClassService, schoolDistrictService;
    //All module dependencies   
    beforeEach(module('your-app-name'));
    
    //inject required services and _$controller_ to create controller
    beforeEach(inject(function(_$compile_,_$controller_, _$rootScope_, _propertyService_, _countyService_, _propertyClassService_, _schoolDistrictService_) {
    
    $compile = _$compile_;
            $rootScope = _$rootScope_;
    $controller = _$controller_; // This is IMP
        countyService = _countyService_;
        // remianig services
        // Now create controller 
        myController = $controller('myController', {
                    $scope : scope,
                    propertyService : propertyService // all other services
        });}
    
    it('should test something', function() {
        spyOn(countyService, 'getAllCountiesAsync').and.callFake(function () {
                    var d = q.defer();
                    d.resolve({ items: [{data:'somedata'}] });
                    return d.promise;
                });     
        myController.getAllCounties();
    
        expect(myController.counties).not.toBe(null);
    
    });
    

    更新

    我可能犯了错误,但这是我的想法:

    describe('service tests', function () {
    
    var $compile, $rootScope, scope, vm, propertyService, countyService, propertyClassService, schoolDistrictService;
      beforeEach(module('your-app-name'));
      beforeEach(inject(function(_$compile_, _$rootScope_, $controller, _propertyService_, _countyService_, _propertyClassService_, _schoolDistrictService_) {
        $compile = _$compile_;
        $rootScope = _$rootScope_;
        scope = $rootScope.$new();
        propertyService = _propertyService_;
        countyService = _countyService_;
        propertyClassService = _propertyClassService_;
        schoolDistrictService = _schoolDistrictService_;
    
        vm = $controller('myController', {'$scope': scope})
    
        spyOn(countyService, "getAllCountiesAsync").and.callFake(function() {
            var deferred = $q.defer();
            deferred.resolve({data: [{id:0}]});
            return deferred.promise;
        });
      }));
    
      it('can do remote call', inject(function() {
    
        //Arrange
        result = [{id:0}];
    
        // Act
        vm.getAllCounties();
    
        // Assert
        expect(vm.counties).toBe(result); //assert to whatever is resolved in the spyOn function
    
      });   
    
    });
    }
    

    【讨论】:

    • 您能解释一下it('should test something', function() { 方法吗? B'cos 我对这个主题很陌生。谢谢。
    • 当我们测试任何控制器时,我们应该监视服务(意味着模拟)。在该方法中,我使用了 spyOn 方法来监视 CountyService 的 getAllCountiesAsync 函数。当控制器的方法 get 被调用时,控制器将不会调用实际的服务,而是我们的 spy 将被执行。可能这会帮助你理解。
    • 也就是说,当我们在测试方法中调用myController.getAllCounties();方法时,它会调用模拟服务(spyOn)吗?如果是这样,测试的数据来自哪里(因此它没有调用 webApi 上的实际服务)?上面显示的测试方法中myController.counties 的值是多少?谢谢。
    • 数据将来自间谍服务。在我们的例子中,数据将是 { items: [{data:'somedata'}] } 对象。在为控制器编写测试用例时,我们的重点应该放在控制器代码而不是服务上。对于服务必须编写不同的测试用例文件。
    • 你知道在不注入所有服务的情况下测试控制器的技巧或概念吗?我上面的控制器上的 B'cos 有超过 50 项服务。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2016-09-18
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 2012-07-10
    • 1970-01-01
    • 2014-08-15
    相关资源
    最近更新 更多