问题
I work on a large Angular App and initially we done a lot of our tests by using $provide to mock services. However we now have a lot of Jasmine Spies in our tests in order to stub and spy on services.
i.e
spyOn(myService, 'myMethod').andReturn 'myValue'
Should we really be using $provide for this or are there cases where spying on a service is the best approach?
In the Angular Tests they use spies for spying on Jquery which I would see as an external service.
spyOn(jq.prototype, 'on');
$provide seems to be used more for internal services.
module(function($provide){
$provide.provider('$exceptionHandler', $ExceptionHandlerProvider);
});
There is also a Jasmine createSpy function but now I'm thinking that $provide should always take precedence over that.
Any insights or help in this would be appreciated.
回答1:
From my own (limited) experience, I would say do whatever approach makes:
- The test code simpler / clearer / shorter
- Limits the assumptions about what the code your testing does internally.
- Reduces its side-affects (like running actual Ajax requests)
- Keeps the test as short as possible, in terms or run time.
Usually the spyOn
approach works when, in order to do the above, I would like to stub a single method from a service / factory. If I need to mock an entire service / factory, then use $provide
.
A few specific cases come to mind that require one or the other:
If you're testing a service, then to stub other methods from that service, you'll have to use
spyOn
To ensure that extra dependencies aren't introduced later in the code under test, than
$provide
adds a bit more protection. Say, if you want to ensure thatServiceA
only requiresmyMethod
fromServiceB
, then$provide
I think would be the way to go, as ifServiceA
calls any undefined methods fromServiceB
during the test, errors would be raised.$provide.provider('ServiceB', { myMethod: function() {} });
If you want to mock a factory that returns a function, so:
app.factory('myFactory', function() { return function(option) { // Do something here } });
Which is used as:
myFactory(option);
Then to verify that some code calls
myFactory(option)
I think there is no alternative then to use$provide
to mock the factory.
Just by the way, they're not mutually-exclusive options. You can use $provide
and then still have spies involved. In the previous example, if you want to verify the factory was called with an option, you might have to:
var myFactorySpy = jasmine.createSpy();
$provide.provider('myFactory', myFactorySpy);
And then in the test at the appropriate point:
expect(myFactorySpy).toHaveBeenCalledWith(option);
来源:https://stackoverflow.com/questions/22946821/when-should-i-use-provide-versus-jasmine-spies-in-my-angular-js-unit-tests