简体   繁体   English

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

[英]How do you mock Angular service that is a function?

We have a what we call a CORShttpService , which is basically a wrapper aroung the $http service, but encapsulates some CORS functionality that we need. 我们有一个我们称之为CORShttpService ,它基本上是一个包含$http服务的包装器,但是封装了我们需要的一些CORS功能。 I'm now writing some tests for a service that has the CORShttpService injected into it. 我现在正在为一个注入了CORShttpService的服务编写一些测试。 This service has code like this: 此服务的代码如下:

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

I want to mock the call to CORShttpService , but I'm not sure how to go about doing it. 我想模拟对CORShttpService的调用,但我不知道如何去做。 I'm using Jasmine, and its spyOn function requires an object to mock the function on the object. 我正在使用Jasmine,它的spyOn函数需要一个对象来模拟对象上的函数。 My CORShttpService isn't attached to any object, so I don't know how to go about mocking it. 我的CORShttpService没有附加到任何对象,所以我不知道如何嘲笑它。 Yes, I could use $httpBackend to mock the requests that eventually get set in the CORShttpService , but I don't want it going into that service in the first place. 是的,我可以使用$httpBackend来模拟最终在CORShttpService设置的CORShttpService ,但我不希望它首先进入该服务。 I want to isolate the unit test and simply mock the external calls. 我想隔离单元测试并简单地模拟外部调用。 Is there any way I can mock this service that is just a function? 有什么方法可以嘲笑这个只是一个功能的服务吗?

As I thought about this more, the $httpBackend service does provide a lot of functionality for testing requests. 正如我对此的想法更多, $httpBackend服务确实提供了许多测试请求的功能。 As my CORShttpService is a basically a wrapper around $http , I decided I could probably get the most bang for my buck, if I made the mock implementation of CORShttpService simple the $http implementation. 因为我的CORShttpService基本上是一个围绕$http的包装器,所以我决定我可能会获得最大的CORShttpService ,如果我将CORShttpService的模拟实现简单化为$http实现。 Using this documentation to help me, I have the following in my spec: 使用此文档来帮助我,我的规范中包含以下内容:

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

So, any of my services wanting the CORShttpService injected, will now basically just have $http injected, and thus allow me to use all the $httpBackend functionality without the concern of the extra functionality found in the CORShttpService itself. 因此,我想要注入CORShttpService任何服务现在基本上CORShttpService注入了$http ,因此允许我使用所有$httpBackend功能而不用担心CORShttpService本身中的额外功能。

This works for my specific case, but as far as a general solution for mocking services that are just a function, the same kind of thing could probably be done with jasmine.createSpy as mentioned in zbynour's answer. 这适用于我的具体情况,但就jasmine.createSpy服务只是一个函数的一般解决方案而言,可能使用zbynour的答案中提到的jasmine.createSpy来完成同样的事情。 Something like: 就像是:

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

Yes, as you wrote spyOn can stub a function but it has to be property of already existing object. 是的,正如您所写, spyOn可以存根函数但它必须是已存在对象的属性。 I also agree it's better to isolate the unit. 我也同意隔离该单元更好。 :) :)

What you need is jasmine.createSpy . 你需要的是jasmine.createSpy By that you can create a bare spy and define its behavior as usual (using andReturn , andCallFake , etc.). 通过这种方式,您可以创建一个裸间谍并像往常一样定义其行为(使用andReturnandCallFake等)。

I think something like the code below (also with jasmine.createSpyObj ) cloud be what you want: 我认为类似下面的代码(也使用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));
});

In case you want to go further, instead of simple 如果你想进一步,而不是简单

res.success.andReturn(res);

you can store the callback passed in 你可以存储传入的回调

var succCallback;
res.success.andCallFake(function(callback) {
        succCallback = callback;
        return res;
    });

and later in the spec you can call the callback to emulate the success result from the corsHttpService : 稍后在规范中,您可以调用回调来模拟corsHttpService的成功结果:

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

Then it's possible to test 'success stuff' of tested service... 然后就可以测试经过测试的服务的“成功之物”......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM