Rails - 使用Obj.find()停止测试环境创建新对象?

时间:2013-01-19 11:14:28

标签: ruby-on-rails ruby

我正在关注敏捷书籍,我无法让我的单元测试表现得很好。问题是在rake test:functionals期间创建了两个对象而不是一个。我已经确定了原因,但我无法解决问题。

以下是相关代码:

class CartsController < ApplicationController
  def create
    @cart = Cart.new(params[:cart])
    session[:cart_id] = @cart.id

    respond_to do |format|
      if @cart.save
        format.html { redirect_to @cart }
        format.json { render json: @cart, status: :created, location: @cart }
      else
        format.html { render action: "new" }
        format.json { render json: @cart.errors, status: :unprocessable_entity }
      end
    end
  endnormal

当它重定向到@cart时,它调用application_controller,它包含以下代码:

class ApplicationController < ActionController::Base
  protect_from_forgery
  before_filter :the_cart

  private

    def the_cart
      @cart = current_cart
    end

    def current_cart
      Cart.find(session[:cart_id])
    rescue ActiveRecord::RecordNotFound
      cart = Cart.create
      session[:cart_id] = cart.id
      cart
    end

正常 在开发环境中,当session [:cart_id]已经有购物车时,current_cart将不会创建另一个购物车。但是在测试环境中,只需运行Cart.find(session [:cart_id])就可以创建一个新的Cart项目。我如何解决这个问题,以便.find每次都不为测试环境创建一个新对象?

编辑:这是失败的测试

  test "should create cart" do
    Rails::logger.debug "CREATING CART"
    Rails::logger.debug Cart.all.to_a
    assert_difference('Cart.count') do
      post :create, cart: {  }
      Rails::logger.debug Cart.all.to_a
    end

    assert_redirected_to cart_path(assigns(:cart))
  end

2 个答案:

答案 0 :(得分:1)

我没有看到任何可能使测试行为不同的内容,但您的代码对我来说是错误的。 对于每个请求,before_filter将加载现有购物车,如果不存在,则创建一个新购物车。

在运行之前的过滤器之后,操作将会运行,这将创建一个购物车而不检查是否存在,因此创建了第二个购物车

您的before_filter和您的创建操作都在创建购物车。先前过滤器首先运行并创建一个,然后运行创建操作并且(不检查购物车的存在)创建另一个。

如果在任何时候为您创建了购物车,我不确定您为何会采取create行动。您可以跳过该过滤器以进行创建操作,也可以更改创建操作,以便它使用该过滤器创建的购物车(尽管这会导致创建操作只是一个更新操作,这有点奇怪)< / p>

答案 1 :(得分:0)

如果您正在使用请求规范或集成测试,这可能不会创建2个购物车,因为在这些类型的测试中正确遵循重定向。其他测试,单独测试,我在测试中设置时不知道会话变量。这是在看到测试之前编写的。

你在使用灯具吗?也许购物车已经装好了。尝试将pry添加到您的gem文件中。然后在您的测试中,调试语句放在binding.pry,您将进入测试控制台,并执行Cart.count以查看存在多少购物车。