测试非公共路线会导致KeyError

问题描述

我是Crystal和Amber的新手,并且在测试非公共路线时遇到问题。我使用了Amber身份验证生成器,然后为Job实体生成了一个支架,并将相关的路由添加到route:auth块。 当我打开浏览器并尝试直接进入工作路线时,所有操作均按预期进行,并且重定向到登录页面。

但是当我为JobsController执行生成的测试时,出现以下错误:

1) JobControllerTest renders job index template
       Missing hash key: :auth (KeyError)
         from ../../.asdf/installs/crystal/0.35.1/src/hash.cr:1030:9 in ‘[]’
         from lib/amber/src/amber/pipes/pipeline.cr:19:15 in ‘call’
         from lib/garnet_spec/src/garnet_spec/controller/test.cr:25:7 in ‘process_request’
         from spec/controllers/job_controller_spec.cr:20:1 in ‘get’
         from spec/controllers/job_controller_spec.cr:39:5 in ‘->’
         from ../../.asdf/installs/crystal/0.35.1/src/primitives.cr:255:3 in ‘internal_run’
         from ../../.asdf/installs/crystal/0.35.1/src/spec/example.cr:33:16 in ‘run’
         from ../../.asdf/installs/crystal/0.35.1/src/spec/context.cr:18:23 in ‘internal_run’
         from ../../.asdf/installs/crystal/0.35.1/src/spec/context.cr:330:7 in ‘run’
         from ../../.asdf/installs/crystal/0.35.1/src/spec/context.cr:18:23 in ‘internal_run’
         from ../../.asdf/installs/crystal/0.35.1/src/spec/context.cr:147:7 in ‘run’
         from ../../.asdf/installs/crystal/0.35.1/src/spec/dsl.cr:270:7 in ‘->’
         from ../../.asdf/installs/crystal/0.35.1/src/primitives.cr:255:3 in ‘run’
         from ../../.asdf/installs/crystal/0.35.1/src/crystal/main.cr:45:14 in ‘main’
         from ../../.asdf/installs/crystal/0.35.1/src/crystal/main.cr:114:3 in ‘main’

routes.cr

routes :auth do
 ...
 resources "jobs",JobController
end

JobControllerTest.cr

...
class JobControllerTest < GarnetSpec::Controller::Test
  getter handler : Amber::Pipe::Pipeline

  def initialize
    @handler = Amber::Pipe::Pipeline.new
    @handler.build :web do
      plug Amber::Pipe::Error.new
      plug Amber::Pipe::Session.new
      plug Amber::Pipe::Flash.new
    end
    @handler.prepare_pipelines
  end
end

describe JobControllerTest do
  subject = JobControllerTest.new

  it “renders job index template” do
    Job.clear
    response = subject.get “/jobs” # -> line 39 where the error happens
    response.status_code.should eq(302)
    response.body.should contain(“jobs”)
  end
end
...

我没有在Ambers文档中找到任何信息,也没有在Google上找到任何信息。我的问题如下:

  • 我应该如何提供身份验证数据?以及为什么在退出后应用程序重定向后我根本没有?
  • 对于控制器规格是否有任何测试帮助程序可以使用户登录,从而可以 对经过身份验证的用户进行测试?

解决方法

您需要在初始化函数中包含auth处理程序吗?

@handler.build :auth do
    plug Authenticate.new
end

[更新] 添加了用于添加登录测试的指针。

要测试已验证的路由,可以使用https://docs.amberframework.org/amber/guides/testing/system-tests

中记录的系统测试

我没有太多关于进行系统测试的可用API调用的文档。但是从这段代码中,我了解到页面加载后,您可以填写登录名和密码并模拟click事件。 https://github.com/amberframework/garnet-spec/blob/master/src/garnet_spec/system_test.cr

fill(:class_name,"login","test_username")
fill(:class_name,"password","test_pass")
click(:class_name,"login-button")

我尚未测试代码,请根据可用文档在此处更新注释。

,

对于您的第二个问题,如果您使用 Amber 附带的基本身份验证,我将以下内容添加到我的 spec_helper.cr 中,并且能够通过从类继承来对经过身份验证的用户进行控制器测试。它确实需要 crystagiri 分片,以便您能够获得 csrf_token。

require "../spec_helper"
require "crystagiri"


def login_params(csrf_token)
  params = [] of String
  params << "email=admin@example.com"
  params << "password=password"
  params << "_csrf=#{csrf_token}"
  params.join("&")
end

def create_user
    user = User.new(email: "admin@example.com",first_name:"Test",last_name:"User")
    user.password = "password"
    user.save
    user
end

def get_csrf_token(response_body)
  html = Crystagiri::HTML.new response_body
  csrf_token = String.new
  html.where_tag("input") do |back| 
    csrf_token = back.node.attributes[2].content
    break
  end

  csrf_token
end

class ApplicationControllerTest < GarnetSpec::Controller::Test
  getter handler : Amber::Pipe::Pipeline
  getter current_user = User.new
  getter csrf_token = String.new
  setter current_user

  def initialize
    @handler = Amber::Pipe::Pipeline.new

    @handler.build :web do
      plug Citrine::I18n::Handler.new
      plug Amber::Pipe::Error.new
      plug Amber::Pipe::Logger.new
      plug Amber::Pipe::Session.new
      plug Amber::Pipe::Flash.new
      plug Amber::Pipe::CSRF.new

      plug CurrentUser.new
    end

    @handler.build :auth do
      plug Citrine::I18n::Handler.new
      plug Amber::Pipe::Error.new
      plug Amber::Pipe::Logger.new
      plug Amber::Pipe::Session.new
      plug Amber::Pipe::Flash.new
      plug Amber::Pipe::CSRF.new

      plug CurrentUser.new
      plug Authenticate.new
    end
    

    @handler.prepare_pipelines
    @current_user = create_user
  end

  def login_user
    response = get "/signin"
    @csrf_token = get_csrf_token(response.body)
    post "/session",body: login_params(csrf_token),headers: HTTP::Headers{"Cookie" => response.headers["Set-Cookie"]}
  end
end

然后在您的 class_controller_spec.cr 中,当您在发出请求之前需要用户登录时,您将拥有如下内容

class AccountControllerTest < ApplicationControllerTest
 
end

describe AccountControllerTest do
  subject = AccountControllerTest.new

  it "renders account index template" do
    subject.current_user = create_user
    response_headers = subject.login_user.headers
    response = subject.get "/accounts",headers: HTTP::Headers{"Cookie" => response_headers["Set-Cookie"]}

    response.status_code.should eq(200)
    response.body.should contain("accounts")
  end
end

如果您仍在寻找解决方案,希望对您有所帮助!

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...