使用Mocks测试AngularJS服务的初始化

时间:2015-09-08 14:56:40

标签: angularjs unit-testing jasmine angular-mock

我正在尝试测试角度服务在初始化时对其从另一个服务获取的值的响应方式,并且我很难找到一种非笨重的方式来执行它...更不用说有效服务了

我正在尝试测试的服务看起来像这样:

angular.module('myApp')
  .service('myService', function (Auth, DataGrabber) {
    var self = this;

    this.initialize = function () {
       this.user = Auth.getUser();

       if (!this.user.name) {
         DataGrabber.grabName();
       }

       if (!this.user.birthday) {
         DataGrabber.grabBirthday();
       }
    }

    this.initialize();
  })

这是我试图测试它的不那么顺利的方式:

describe('myService', function () {
   var myService;
   var dataGrabberMock;
   var authMock;
   var grabbedName;
   var grabbedBirthday;


   beforeEach(function () {
     module('myApp')
   })

   beforeEach(function() {
     grabbedName = false;
     grabbedBirthday = false;

     authMock = {
       getUser: function () {
         return { 
                  name: 'Bob',
                  birthday: 'Feb 22'
                }
       }
     }

     dataGrabberMock = {
       grabName: function () {
          grabbedName = true;
       },
       grabBirthday: function () {
          grabbedBirthday = true;
       }
     }

     module(function ($provide) {
       $provide.value('Auth', authMock);
       $provide.value('DataGrabber', dataGrabberMock);
     })
   })

   it ('just gets info if all data is present', function () {
     inject(function($injector) {
       myService = $injector.get('myService');
       expect(myService.user.name).toBe('Bob');
       expect(myService.user.birthday).toBe('Feb 22');
     });
   });

   it ('gets info if name is missing', function () {
     // how do I stub the new user response here? 
   })

   it ('calls birthdayGetter if birthday is missing', function () {
     // here too?
   })
})

更改authMock为每个测试提供的值的最简洁方法是什么?

我尝试了大量不同的inject(),$ injector,$ provide和spyOn()组合。我终于通过设置存根和间谍并在测试中显式调用myService.initialize()来实现它,但是每次测试都会运行初始化代码两次,这感觉不对。

我是角度测试的新手,所以当然有一种更好的方法,我可以忽视它作为一个新手。

谢谢!

2 个答案:

答案 0 :(得分:2)

数据分配中存在拼写错误 r 模拟

要更改authMock的值,您可以创建一个单独的方法来设置模拟和注入服务的方法,并在测试中调用它们。

beforeEach(function () {
  grabbedName = false;
  grabbedBirthday = false;

  dataGrabberMock = {
    grabName: function () {
      grabbedName = true;
    },
    grabBirthday: function () {
      grabbedBirthday = true;
    }
  };

  spyOn(dataGrabberMock, 'grabName');
  spyOn(dataGrabberMock, 'grabBirthday');

  module(function ($provide) {
    $provide.value('Auth', authMock);
    $provide.value('DataGrabber', dataGrabberMock);
  });
});

var authMock;

function setupAuthMock(name, birthday){
  authMock = {
    getUser: function () {
      return {
        name: name,
        birthday: birthday
      };
    }
  };
}

function setupAuthMockWithoutName(birthday){
  authMock = {
    getUser: function () {
      return {
        birthday: birthday
      };
    }
  };
}

function setupAuthMockWithoutBirthday(name){
  authMock = {
    getUser: function () {
      return {
        name: name
      };
    }
  };
}

function setupService() {
  inject(function ($injector) {
    myService = $injector.get('myService');
  });
}

it('just gets info if all data is present', function () {
  setupAuthMock('Bob', 'Feb 22');
  setupService();
  expect(myService.user.name).toBe('Bob');
  expect(myService.user.birthday).toBe('Feb 22');
});

it('gets info if name is missing', function () {    
  setupAuthMockWithoutName('Feb 30');
  setupService();
  expect(dataGrabberMock.grabName).toHaveBeenCalled();
});

it('calls birthdayGetter if birthday is missing', function () {
  setupAuthMockWithoutBirthday('Bob');
  setupService();
  expect(dataGrabberMock.grabBirthday).toHaveBeenCalled();
});

答案 1 :(得分:1)

我给了它另一个想法,我认为使用单独的描述块而不是使用单独的方法更清晰。

describe('myService', function () {
  var myService;
  var dataGrabberMock;
  var authMock;
  var grabbedName;
  var grabbedBirthday;

  beforeEach(function () {
    module('myApp');
  });

  beforeEach(function () {
    grabbedName = false;
    grabbedBirthday = false;

    dataGrabberMock = {
      grabName: function () {
        grabbedName = true;
      },
      grabBirthday: function () {
        grabbedBirthday = true;
      }
    };

    spyOn(dataGrabberMock, 'grabName');
    spyOn(dataGrabberMock, 'grabBirthday');

    module(function ($provide) {
      $provide.value('Auth', authMock);
      $provide.value('DataGrabber', dataGrabberMock);
    });
  });

  describe('when all data is present', function () {
    beforeEach(function () {
      authMock = {
        getUser: function () {
          return {
            name: 'Bob',
            birthday: 'Feb 22'
          };
        }
      };
    });

    beforeEach(function () {
      inject(function ($injector) {
        myService = $injector.get('myService');
      });
    });

    it('just gets info', function () {
      expect(myService.user.name).toBe('Bob');
      expect(myService.user.birthday).toBe('Feb 22');
    });
  });

  describe('when name is missing', function () {
    beforeEach(function () {
      authMock = {
        getUser: function () {
          return {
            birthday: 'Feb 22'
          };
        }
      };
    });

    beforeEach(function () {
      inject(function ($injector) {
        myService = $injector.get('myService');
      });
    });

    it('gets info', function () {
      expect(dataGrabberMock.grabName).toHaveBeenCalled();
    });
  });

  describe('when birthday is missing', function () {
    beforeEach(function () {
      authMock = {
        getUser: function () {
          return {
            name: 'Bob',
          };
        }
      };
    });

    beforeEach(function () {
      inject(function ($injector) {
        myService = $injector.get('myService');
      });
    });

    it('calls birthdayGetter', function () {
      expect(dataGrabberMock.grabBirthday).toHaveBeenCalled();
    });
  });
});