为什么这个单元测试承诺包裹$资源失败(但在正在运行的应用程序中工作正常)?

时间:2014-03-08 20:55:43

标签: angularjs jasmine

(我希望我的问题的根源是我没有正确编写单元测试,但我不确定如何纠正它。)

有关详细信息,请参阅两个链接的Plunkers以获取完整代码和解释:

Plunker #1 - 在用户界面中正常工作
运行此plunker以在运行的应用程序中看到它正常工作。请注意,当您键入<input>时,浏览器控制台会显示正在执行的REST调用,每个调用都会附加<input>的更新值作为查询字符串参数。 这在用户界面中按预期工作。

Plunker #2 - 单元测试失败
运行此plunker以查看故障单元测试。 我无法弄清楚为什么这个测试失败了。


我试图让示例掠夺者尽可能简单。掠夺者会显示所有代码,但我会在下面粘贴一些相关代码。

用例是:
 1.当控制器加载时,初始数据通过由promise($ q)包装的$资源加载。 (MultiTagLoader
 2. ng-change触发器<input>触发器中的$scope.searchChange事件在同一个控制器(<input>)中使用expectGET

值执行新查询

这是单元测试。第二个测试总是失败,因为URL与it('should load an initial list of Tags', function () { $httpBackend.expectGET('tags.json?query=DEFAULT_SEARCH_TERM'). respond([{"id": 1, "name": "Hibernate"}, {"id": 12, "name": "JAX-RS"}]); $httpBackend.flush(); expect(scope.tags).toEqualData([{"id": 1, "name": "Hibernate"}, {"id": 12, "name": "JAX-RS"}]); }); it('should invoke search function on scope.searchChange()', function () { $httpBackend.expectGET('tags.json?query=foo'). respond([{"id": 1, "name": "Hibernate"}, {"id": 12, "name": "JAX-RS"}]); scope.searchChange('foo'); $httpBackend.flush(); expect(scope.tags).toEqualData([{"id": 1, "name": "Hibernate"}, {"id": 12, "name": "JAX-RS"}]); }); URL不匹配。

Controller test: ListCtrl should invoke search function on scope.searchChange().
Error: Unexpected request: GET tags.json?query=DEFAULT_SEARCH_TERM 
Expected GET tags.json?query=foo

错误:

myServices.factory('MultiTagLoader', ['TagRestSvc', '$q',
function(TagRestSvc, $q) {
    return {
        query: function(params) {
            var delay = $q.defer();
            TagRestSvc.query(params, function(tags) {
                delay.resolve(tags);
            }, function() {
                delay.reject('Unable to fetch Tags');
            });
            return delay.promise;
         }
    };
}]);

控制器代码(如掠夺者所见)正在调用此工厂:

{{1}}

1 个答案:

答案 0 :(得分:1)

将在每个规范之前创建控制器的新实例。这意味着默认请求不仅会出现在您的第一个规范中,也会出现在您的第二个规范中。

虽然你可以通过将第一个规范中的请求期望添加到第二个规范来解决这个问题,但这并不是你想要的。相反,您希望为整个套件设置后端定义。

例如:

beforeEach(inject(function (_$httpBackend_, $rootScope, $controller) {
    $httpBackend = _$httpBackend_;

    scope = $rootScope.$new();

    ctrl = $controller('ListCtrl', {
        $scope: scope
    });

    $httpBackend.whenGET('tags.json?query=DEFAULT_SEARCH_TERM').respond([{"id": 1, "name": "Hibernate"}, {"id": 12, "name": "JAX-RS"}]);
}));

$ httpBackend documentation解释了request expectationbackend defintion之间的差异:

  

请求期望提供了一种对请求进行断言的方法   由应用程序制作并定义对这些请求的响应。   如果没有做出预期的请求,那么测试将失败   订单错误。

     

后端定义允许您为您的后端定义假后端   如果提出特定请求或不提出声明的应用程序   不是,如果提出请求,它只返回训练有素的响应。考试   无论是否在测试期间提出请求,都会通过。

如果未添加默认请求,则添加新的后端定义后,您的第一个规范仍将失败,因为它包含对它的期望。但是,如果未进行searchChange请求,则您的第二个规范将失败。它仍然会发出默认请求并从后端定义中获取响应数据,但如果没有请求则不会失败。您可以观察到这是从控制器中删除默认请求。

演示规范的演示: http://plnkr.co/edit/yCOVReYvYEHQXeSKE0ja?p=preview