【问题标题】:How to test javascript redirection without redirecting?如何在不重定向的情况下测试javascript重定向?
【发布时间】:2011-05-27 14:55:23
【问题描述】:

我正在使用 Jasmine 进行一些测试,尽管这通常可以应用于基于浏览器的 javascript 单元测试。

我有一个功能,在某些情况下使用window.location.assign 将用户重定向到不同的页面。问题是,如果到达这一行,页面就会被重定向。在这种情况下,由于它被重定向到'/',页面重新加载,所有测试再次运行。我可以做些什么来测试函数到达它重定向的行,没有重定向

【问题讨论】:

  • 可以修改页面源吗?
  • 修改页面源代码会使单元测试非常具有侵入性。

标签: javascript unit-testing jasmine


【解决方案1】:

我也遇到过同样的问题。我的解决方案是将实际重定向分解为单一用途的功能。也就是说,不做任何条件检查或其他逻辑,只是重定向。 说这是旧代码...

function redirect() {
 if(something) {
  window.location = "/";
 else if(somethingElse)
  window.location = "/?a=42";
 else
  window.location = "/derp";
}

我会把它改成..

function redirect() {
 if(something) {
  doRedirect("/");
 else if(somethingElse)
  doRedirect("/?a=42");
 else
  doRedirect("/derp");
}

function doRedirect(href) {
 window.location = href;
}

然后你可以spyOndoRedirect 函数来确保重定向函数传递的条件正确的URI。

【讨论】:

  • 我更喜欢不涉及更改我的 JS 代码的方法。不幸的是,我可能别无选择。
  • 幸运的是,这是一个相当微不足道的改变,我也一直想要一个更好的解决方案,但这是我唯一想到的。
【解决方案2】:

这是一个完整的示例,用于测试单击购买按钮是否使用@Morgan 提到的方法将用户重定向到外部 URL。

# navigation.coffee
exports.goToExternalUrl = (url) ->
    window.location = url


# myView.coffee
Navigation = require("lib/navigation")

exports.MyView = Backbone.View.extend
  events:
    "click .purchase":"purchase"

  purchase: ->
    Navigation.goToExternalUrl("http://amazon.com/someproduct")


# my_view_spec.coffee
Navigation = require("lib/navigation")
MyView = require("myView").MyView

describe("MyView"), ->
  it "can be purchased", ->
    # this line prevents the location.href from actually being set
    spyOn(Navigation,'goToExternalUrl').andCallFake (->)

    $el.find('.purchase').trigger('click')
    expect(Navigation.goToExternalUrl).toHaveBeenCalled()

【讨论】:

    【解决方案3】:

    这里的困难在于您的代码依赖于全局变量window,因此您无法在测试中轻松替换该依赖项。这是我在类似情况下所做的基本想法。编写代码,使window 只能被间接访问,除非在初始化期间它被保存到本地/实例变量中。

    var unit = {
      initialize: function () {
        this.window = window;
      },
      codeThatRedirects: function (newUrl) {
        this.window.location.href = newUrl;
      }
    };
    

    现在你可以用别的东西替换unit.window,可能是这样的:

    unit.initialize();
    unit.window = {
      location: {
        href: "dummy"
      }
    };
    
    unit.codeThatRedirects('http://new.url.com');
    
    assert(unit.window.location.href === "http://new.url.com");
    

    【讨论】:

    • 如果您尝试在浏览器运行测试中重新定义窗口,您会注意到一些非常奇怪的行为。它不是一个实际的变量。
    • 这段代码不是重新定义窗口。它只是重新定义了一个曾经包含对 window 的引用的变量,因此它现在包含对另一个对象的引用。
    • 我知道你想做什么,是的。但试着实际去做。打开开发者控制台并尝试一下。你会感到惊讶。例如,在 Chrome 中,它会忽略您重新分配它的尝试。
    • 我不确定你是如何得到这种行为的。你说哪个作业失败了?我刚刚在 Chrome 开发者控制台中尝试过它,它的行为符合预期。将代码复制并粘贴到开发人员控制台中,但将最后一条语句替换为unit.window.location.href === "http://new.url.com"(因为assert 是假的)。它应该返回 true。
    【解决方案4】:

    您可能会考虑使用 GreaseMonkey 来更新 javascript,但这仍然有些干扰...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-10
      • 2017-07-06
      • 2017-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多