Angularjs和Jasmine:使用服务进行ajax调用来测试控制器

时间:2014-02-13 11:21:02

标签: angularjs unit-testing jasmine

我对测试javascript非常新。我的应用程序使用angularjs。我使用茉莉作为测试框架。

这是我正在测试的控制器:

angular.module('logonController', ["ngval", "accountFactory"])
    .controller("logonController", function logOnController(accountFactory, $scope, $window) {
        $scope.hasServerError = false;
        $scope.Logon = function () {
            accountFactory.Logon($scope.data.LogOnModel)
                .then(function (data) {
                    $window.location.href = "/";
                },
                function (data) {
                    $scope.hasServerError = true;

                });
        }

    }) 

其中accountFactory.Logon向服务器发出Post请求。

我想测试的是调用accountFactory.Logon

  1. 成功时 - window.location.href被称为
  2. 错误$scope.hasServerError设置为true
  3. 到目前为止,我设法做到了这一点:

    "use strict";
    
    describe("Logon Controller", function () {
    
        var $scope, $location, $rootScope, $httpBackend, $controller, $window, createController;
    
        beforeEach(function () {
            module("logonController");
        });
    
        beforeEach(inject(function ($injector) {
            $rootScope = $injector.get("$rootScope");
            $scope = $rootScope.$new();
            $location = $injector.get("$location");
            $httpBackend = $injector.get("$httpBackend");
            $controller = $injector.get("$controller");
            $window = $injector.get("$window");
        }));
    
        beforeEach(function () {
            createController = function () {
                return $controller("logonController", {
                    "$scope": $scope,
                });
            };
    
            $scope.data = {
                LogOnModel: { username: "user", password: "pass" }
            };
    
            $window = { location: { href: jasmine.createSpy() } };
        });
    
        it("should redirect on successfull login", function () {
            var controller = createController();
    
            $httpBackend.whenPOST("/Account/Logon").respond(function (method, url, data, headers) {
                return [200, {}, {}];
            });
    
            $scope.Logon();
    
            $httpBackend.flush();
    
            expect($window.location.href).toHaveBeenCalled();
        });
    });
    

    我的想法是在$ window.location.href上创建一个间谍,只检查它是否被调用。但我得到了

      

    未知的间谍被称为。

    正如我所说,我对测试javascript非常陌生,所以任何帮助都会受到赞赏。

2 个答案:

答案 0 :(得分:3)

Sten Muchow的答案在几个方面是错误的:

  1. 您不能将复合属性名称(" location.href")指定为spyOn的第二个参数。你必须提供一个不动产的名称。
  2. 即使你正确地执行spyOn,andCallThrough()仍会引发异常,因为$ window.location.href不是可以调用的函数。
  3. 但他仍然说你不应该将控制器测试与服务测试混合在一起。

    回答这个问题:

    你的期望未得到满足(甚至间谍仍然存在*)的原因是你在promise' then()函数中进行了$ window.location.href赋值。这意味着,它将异步执行,即在您的expect()调用之后。要解决这个问题,您需要异步进行测试(对于如何执行此操作,我建议您使用Jasmine文档:http://jasmine.github.io/2.0/introduction.html)。

    *在accountFactory.Logon中,通过执行$window.location.href =(即分配),您将有效地覆盖您的间谍。

    更好的解决方案:

    您应该使用$window.location.href,而不是操纵$location.url()

    $location是一个Angular核心服务。您将受益于Angular应用程序生命周期中的集成(即,当URL更改时,将自动处理观察者)+它与历史API等现有HTML5 API无缝集成:https://docs.angularjs.org/guide/ $ location

    然后,你可以监视$ location.url(),就像你在$ window.location.href上监视一样(如果它是一个函数)。

答案 1 :(得分:-1)

你需要创建一个间谍:

spyOn($window, 'location.href').andCallThrough();

但更重要的是,你不应该在控制器测试中测试你的服务功能。