【问题标题】:Testing calling of method on injected Service在注入的服务上测试方法调用
【发布时间】:2016-05-11 05:33:15
【问题描述】:

试图弄清楚如何检查注入服务上的方法是否被调用。

服务(基于工厂):loginService.js

angular.module('loginService', [])
    .factory('loginService', function (URLbase, $http, loginModel, $route, $location, logoutService, overviewService) {
        return {
            logMeIn: function (login) {

                $http({
                    method: 'POST',
                    url: URLbase + 'authentication/login',
                    data: {'Login': login.username, 'Password': login.password}
                }).then(function (result) {

                        loginModel.set('passwordRequested', false);
                        loginModel.set('loginFailed', false);
                        loginModel.set('loginExpired', false);
                        loginModel.set('loginBlocked', false);
                        loginModel.set('loggedIn', false);
                        loginModel.set('sessionExpired', false);
                        loginModel.set('loggedIn', false);
                        loginModel.set('concurrentLogin', false);
                        loginModel.set('somethingWrong', false);

                        // Check login result by status code
                        var status = result.data.Response.Status.StatusCode,
                            data = result.data.Response.Payload;

                    switch (status) {
                        case 0:
                            loginModel.set('tokenToken', data.Token);
                            loginModel.set('tokenUserId', data.userId);
                            loginModel.set('userName', data.User.FirstName + ' ' + data.User.SurName);
                            loginModel.set('userFirstName', data.User.FirstName);
                            loginModel.set('userLastName', data.User.SurName);
                            loginModel.set('userEmailAddress', data.User.Email);
                            loginModel.set('userPhone', data.User.Phone);
                            loginModel.set('userPreferredLanguage', data.User.PreferredLanguage);
                            loginModel.set('loggedIn', true);
        ......

单元测试

beforeEach(inject(function ($controller, _$rootScope_, _$httpBackend_, $injector, _loginService_, _loginModel_) {
    loginService = _loginService_;
    httpBackend = _$httpBackend_;
    $rootScope = _$rootScope_;
    loginModel = _loginModel_;

    loginPost = {'Login': login.username, 'Password': login.password};
    httpBackend.whenPOST(URLbase + 'authentication/login', loginPost).respond(200, jsonObj);
}));

it('should get login data from the backend', function () {

    spyOn(loginService, 'logMeIn').andCallThrough();
    loginService.logMeIn(login);
    expect(loginService.logMeIn).toHaveBeenCalledWith(login);
    httpBackend.flush();

    //spyOn(loginModel, 'set').andCallThrough();
    //loginService >> logMeIn >> loginModel.set('userLastName', 'Vijver');
    //metod >> toHaveBeenCalledWith('userLastName', 'Vijver');
});

因此,在最后 3 行注释中,我想测试是否使用正确的参数调用 loginModel.set('userFirstName', data.User.FirstName);

我该如何管理?

【问题讨论】:

    标签: angularjs unit-testing dependency-injection factory karma-jasmine


    【解决方案1】:

    您可以在调用本身内部测试结果:

    logService.logMeIn(login).then(function(result) {
      expect(loginModel.set).toHaveBeenCalledWith('userFirstName',data.User.FirstName);
    });
    

    编辑

    你的函数应该这样做:

    return {
            logMeIn: function (login) {
    
                return $http({..
            }
    }
    

    编辑

    关于您的 switch 语句,我会这样做,因为我希望将成功和失败的部分尽可能小:

    $http({
      method: 'POST',
      url: URLbase + 'authentication/login',
      data: {'Login': login.username, 'Password': login.password}
    }).then(function (result) {
    
      // This underscore is lodash syntax - which I'd recommend
      var loginStuff = ['passwordRequested','loginFailed','loginExpired',etc];
      _.forEach(loginDetails, function(detail) {
        loginModel.set(detail, false);
      });
      // Here I have immediately removed lines of redundant code.
      // I'd also suggest you go one further and place this into it's own    
      // function - which can be private to the service if you choose
    });
    

    同样的原则也可以应用于交换机。如果没有看到所有的 switch case,我就无法正确地重构它。

    【讨论】:

    • 有道理,实现了,但我收到错误TypeError: Cannot read property 'then' of undefined
    • @SanJayFalcon 那是因为您没有返回承诺。更改您的 logMeIn() 函数以将其返回。查看我的编辑
    • 这行得通,但是,函数'loginModel.set'存在于某个开关案例中。我现在强制代码通过一个不同的 switch case 运行,它不包含这个函数,但测试仍然成功。 loginModel.set 好像是单独测试的,需要作为loginService 上的属性进行测试吗?
    • @SanJayFalcon 我建议将代码移到 switch 块之外,以便对其进行正确测试。如果它只存在于开关块内,则 1 - 开关块变得太大,2 - 更难测试。理论上 - 如果代码是用简洁的原则编写的,测试应该很容易
    • 我不知道该怎么做。登录过程应对 5 种情况作出反应。 Switch 或 if/else 实现似乎合乎逻辑。你能更准确地说出你的看法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多