【问题标题】:Angularjs and Jasmine: Testing a controller with a service making ajax callAngularjs 和 Jasmine:使用进行 ajax 调用的服务测试控制器
【发布时间】:2014-02-13 11:21:02
【问题描述】:

我对测试 javascript 非常陌生。我的应用程序正在使用 angularjs。我正在使用 jasmine 作为测试框架。

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

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

到目前为止,我已经做到了:

"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 的新手,因此我们将不胜感激。

【问题讨论】:

    标签: angularjs unit-testing jasmine


    【解决方案1】:

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

    1. 您不能将复合属性名称(“location.href”)指定为 spyOn 的第二个参数。您必须提供真实的房产名称。
    2. 即使您正确执行了 spyOn,andCallThrough() 仍然会引发异常,因为 $window.location.href 不是可以通过调用的函数。

    但他说你不应该将控制器测试与服务测试混为一谈仍然是对的。

    回答问题:

    未满足您的期望(甚至间谍仍然存在*)的原因是,您在 promise 的 then() 函数中执行 $window.location.href 分配。这意味着,它将异步执行,即在您的 expect() 调用之后。为了解决这个问题,你需要让你的测试异步工作(关于如何做到这一点,我想建议你参考 Jasmine 文档:http://jasmine.github.io/2.0/introduction.html)。

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

    更好的解决方案:

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

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

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

    【讨论】:

      【解决方案2】:

      你需要创建一个间谍:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-07
        • 1970-01-01
        • 1970-01-01
        • 2014-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-03
        相关资源
        最近更新 更多