当使用带有RSpec的factory_bot(以前的factory_girl)在Rails中测试时,未定义的方法“first”

时间:2017-10-23 07:03:44

标签: ruby-on-rails ruby rspec factory-bot

我有一个使用factory_bot创建实例的RSpec测试。测试通过,除非在视图中使用第一个方法。

这是正在测试的代码:

def order_confirm_email(id, items, order, address, coupon)
    @user = User.find(id)
    @items = items
    @order = order
    @address = address
    if coupon == nil
      @coupon = ''
    else
      @coupon = coupon.discount
    end

    mail(to: @user.email, subject: 'Order completed')
  end

这是测试:

it 'sends an email upon checkout process completion' do
      user    = create(:user)
      items   = create(:base_item)
      order   = create(:base_item)
      address = create(:address)
      coupon  = create(:coupon)

      expect(orderConfirmationMail.subject).to eq('Order completed')
    end

到目前为止一切顺利。但是当其中一个视图尝试访问第一个实例时,如下所示:

<h1>Order id - <%= @order.first.id %></h1>

然后我收到以下错误:

Failures:

  1) UserMailer user_emails sends an email upon checkout process completion
     Failure/Error: <!-- <h1>Order id - <%= @order.first.id %></h1> -->

     ActionView::Template::Error:
       undefined method `first' for 3:Fixnum

根据我的理解,实例应该是持久的,因为我使用 create 而不是 build 。但显然这种情况并没有发生。除非作为最后的手段,否则不能更改视图。我该如何解决这个问题?

更新1:

这是 order_items.rb 工厂文件:

FactoryBot.define do
  factory :base_item, class: OrderItem do
    item_name_en "Sample Item"
    item_link "http://www.foo.com"
    qty 5
    available_qty 100
    item_price 10
    seller_name "foo"
    status "foo"

    foo_item_id "123456"
    foo_id "654321"
  end

  factory :order_item1, parent: :base_item do
    foo_item_id "123456"
    foo_seller_id "654321"
    association :order
  end

  factory :order_item2, parent: :base_item do
    foo_item_id "123457"
    foo_seller_id "654321"
  end

  factory :order_item3, parent: :base_item do
    foo_item_id "123458"
    foo_seller_id "654322"
  end
end

更新2:

我在编写另一个测试时遇到了类似的问题。我收到以下错误:

Failures:

  1) UserMailer user_emails sends an email upon abandoned cart
     Failure/Error: <% @items.each do |item| %>

     ActionView::Template::Error:
       undefined method `each' for 1:Fixnum

这似乎表明它不是第一个方法本身的问题,而是在运行RSpec时视图中插入的Ruby会引发错误。这概括了问题,并希望使其更容易解决。

2 个答案:

答案 0 :(得分:2)

  

这不是问题,因为我在规范中的前面包含了我知道正常工作的这一行,因为我在另一个测试中成功使用了相同的格式

     

let(:orderConfirmationMail) { UserMailer.order_confirm_email(1,2,3,4,nil) }

就是这样。如果你从一开始就包括这一行,你的问题就会在两秒内得到解答。

考虑order_confirm_email

的签名
def order_confirm_email(id, items, order, address, coupon)

为什么您认为order设置为3? 因为你以这种方式传递它!

神秘解决了。

答案 1 :(得分:0)

抱歉,我什么都不知道。我会看一下你的$(document).ready(function () { $("#form").submit(function (e) { //e.preventDefault(); var data =$(this).serialize(); insertStudent(data); return false; }); function insertStudent(data) { $.ajax({ url: 'process.php', data: data, type: 'post', dataType: 'html', success: function (data, textStatus) { $("#result").html(data); // console.log(data); }, error: function () { alert('Not OKay'); } }); } }); 模型,我也不明白你为什么OrderItem,因为那只是一个对象。可能对我@order.first而不是@orders.first有意义。当事情在@order.first中没有意义时,很难构建应用程序。 railsorder应该是两个不同的模型,我们使用item来建立两个不同模型之间的联接

订单可以有多个或只有一个项目,您可以决定关系。

使用order_items您可以调试,也可以在rspec环境中测试您的工厂。在那里,您可以查看rails c testcreate(:base_item)

的结果

我认为这应该是一个对象,所以我不明白它为什么会说FactoryGirl.create(:base_item)

也许你undefined method 'first' for 3:Fixnum不是我们所期望的

但您可以通过在工厂的控制台中调试和测试来理解这一点