Angular服务中的单元测试$ q承诺 - Karma,Jasmine

时间:2017-03-13 02:14:12

标签: javascript angularjs unit-testing jasmine karma-jasmine

我正在尝试使用Karma和Jasmine对Angular服务进行单元测试。我正在制作一些关于如何从控制器单元测试服务调用的教程,但我希望在服务本身内进行单元测试。 UsersService.findById()进行异步调用以在ID中查找ID,但我无法弄清楚如何编写通过测试。我很亲密,但我需要一些帮助。这是UsersService中的函数

users.service.js

        Users.findById = function(id){
            var deferred = $q.defer();

            deferred.resolve(userList.find(function(user){
                return user.id == id;
            }));

            return deferred.promise;
        };

以下是规范:

users.service.spec.js

describe("Users Factory", function(){
    var UsersService, $q, $rootScope, $provide, deferred, mockedDeferred;

    var userList = [
        { id: 1, name: "Richard Hendricks", email: "richard@piedpiper.com", phone: 4085550011, pokemon: { isPresent: true, name: "eevee"}, icon: { isPresent: false, name: null} },
        { id: 2, name: "Erlich Bachman", email: "erlich@aviato.com", phone: 4155552233, pokemon: { isPresent: true, name: "celebi"}, icon: { isPresent: false, name: null} },
        { id: 3, name: "Gavin Belson", email: "gavin@hooli.com", phone: 9165554455, pokemon: { isPresent: true, name: "snorlax"}, icon: { isPresent: false, name: null} }
    ];

    var singleUser = { id: 2, name: "Erlich Bachman", email: "erlich@aviato.com", phone: 4155552233, pokemon: { isPresent: true, name: "celebi"}, icon: { isPresent: false, name: null} };

    function mockQ(){
        deferred = $q.defer();
        spyOn(UsersService, "findById");
        return deferred;
    }

    beforeEach(angular.mock.module("testing_app"));
    beforeEach(angular.mock.module(function(_$provide_){
        $provide = _$provide_;
    }));

    beforeEach(inject(function(_UsersService_, _$q_, _$rootScope_){
        UsersService = _UsersService_;
        $q = _$q_;
        $rootScope = _$rootScope_;
    }));

    describe("Users.findById()", function(){

        beforeEach(function(){
            mockedDeferred = mockQ();
        });

        it("should exist", function(){
            expect(UsersService.findById).toBeDefined();
        });

        it("should equal singleUser", function(){
            UsersService.findById(2);
            deferred.resolve(userList.find(function(user){
                return user.id == 2;
            }));
            expect(UsersService.findById).toHaveBeenCalled();
            expect(deferred.promise).toEqual(singleUser);
        });
    });
});

这是我在控制台中的内容:

Erlich Bachman, this is your mom. You are not my baby

我很接近,但我如何得到等于singleUser变量的承诺?

1 个答案:

答案 0 :(得分:1)

您正在测试UsersService服务。因此,您的测试用例应该运行该服务并验证其行为是否正确。考虑到这一点,检查调用它的同一函数(测试)上是否调用findById()不提供任何验证,这是多余的和不必要的。在这个特定的测试用例中,更高效的检查将验证该方法是否返回类似Prom的对象(有关详细信息,请参阅here)。另一个生产性检查将是验证已知输入方法的响应值(一旦解决了承诺)。对于后者,您需要做的是在检查承诺的解决值与预期值之前调用$rootScope.$apply();(请参阅angularjs文档中的testing section on promise以获取示例)。一旦我们应用了这个建议,findById()的测试将如下:

describe("Users.findById()", function(){

    it("should exist", function(){
        expect(UsersService.findById).toBeDefined();
    });

    it("should produce a promise", function(){
        var p = UsersService.findById(2);

        expect(p instanceof $q.resolve().constructor).toBeTruthy();
    });

    it("should equal singleUser", function(){
        var p = UsersService.findById(2), resolvedValue;

        p.then(function(value) { resolvedValue = value; });

        $rootScope.$apply();

        expect(resolvedValue).toEqual(singleUser);
    });
});

在某些情况下,被测服务更复杂,并封装了其他低级服务。在这些情况下,您需要监视或模拟这些较低级别的服务,以便通过检查它调用较低级别的服务来验证被测试的较高级别服务是否按预期运行。