你如何模拟作为函数的Angular服务?

时间:2013-01-25 23:23:25

标签: javascript unit-testing angularjs jasmine

我们称之为CORShttpService,它基本上是一个包含$http服务的包装器,但封装了我们需要的一些CORS功能。我现在正在为注入CORShttpService的服务编写一些测试。此服务的代码如下:

CORShttpService({method: requestMethod, url: getUrl(path), data: data}).
    success(function(data, status, headers) {
        //do success stuff
    }).
    error(function(data, status, headers) {
       //do error stuff
    });

我想模仿对CORShttpService的调用,但我不知道如何去做。我正在使用Jasmine,它的spyOn函数需要一个对象来模拟对象上的函数。我的CORShttpService没有附加到任何对象上,所以我不知道如何嘲笑它。是的,我可以使用$httpBackend来模拟最终在CORShttpService中设置的请求,但我不希望它首先进入该服务。我想隔离单元测试并简单地模拟外部调用。有什么方法可以嘲笑这个只是一个函数的服务吗?

2 个答案:

答案 0 :(得分:7)

正如我对此的考虑更多,$httpBackend服务确实提供了许多测试请求的功能。由于我的CORShttpService基本上是$http的包装器,所以我认为如果我将CORShttpService的模拟实现简单$http,我可能会获得最大的收益。实施。使用this documentation来帮助我,我的规范中有以下内容:

beforeEach(module(function($provide) {
    $provide.provider('CORShttpService', function() {
        this.$get = function($http) {
            return $http;
        };
    });
}));

因此,我想要注入CORShttpService的任何服务现在基本上只会注入$http,因此允许我使用所有$httpBackend功能,而无需额外关注CORShttpService本身的功能。

这适用于我的特定情况,但就模拟服务只是一个函数的一般解决方案而言,可能使用zbynour的答案中提到的jasmine.createSpy来完成同样的事情。类似的东西:

beforeEach(module(function($provide) {
    $provide.provider('MyService', function() {
        this.$get = function() {
            return jasmine.createSpy("myService");
        };
    });
}));

答案 1 :(得分:2)

是的,因为您编写spyOn可以存根函数,但它必须是已存在对象的属性。我也同意隔离该单元更好。 :)

您需要的是jasmine.createSpy。通过这种方式,您可以像往常一样创建一个裸间谍并定义其行为(使用andReturnandCallFake等)。

我认为下面的代码(也包含jasmine.createSpyObj)云就像你想要的那样:

it ('should do sth', function() {

    var res = jasmine.createSpyObj('res', [ 'success', 'error' ]);
    res.success.andReturn(res);
    res.error.andReturn(res);
    var corsHttpService = jasmine.createSpy().andReturn(res);

    // call the service using corsHttpService
    anotherService(corsHttpService);

    // assert
    expect(corsHttpService).toHaveBeenCalledWith({
        method: requestMethod, 
        url: url,
        data: data});
    expect(res.success).toHaveBeenCalledWith(jasmine.any(Function));
    expect(res.error).toHaveBeenCalledWith(jasmine.any(Function));
});

如果你想进一步,而不是简单的

res.success.andReturn(res);

您可以存储在

中传递的回调
var succCallback;
res.success.andCallFake(function(callback) {
        succCallback = callback;
        return res;
    });

以及稍后的规范中,您可以调用回调来模拟corsHttpService的成功结果:

succCallback('a-data', 'a-status', 'a-header');

然后可以测试经过测试的服务的“成功之物”......