Rspec - 存档数组以匹配测试数组

Rspec - archives array to match tested array

我在我的 Post 模型上使用这个 class 方法来获取档案

def self.archives
    Post.unscoped.select("YEAR(created_at) AS year, MONTHNAME(created_at) AS month, COUNT(id) AS total")
        .group("year, month, MONTH(created_at)")
        .order("year DESC, MONTH(created_at) DESC")
end

这是我为我的方法编写的测试

context '.archives' do

  first = FactoryGirl.create(:post, published_at: Time.zone.now)
  second = FactoryGirl.create(:post, published_at: 1.month.ago)

  it 'returns articles archived' do
    archives = Post.archives()

    expect(
      [{
        year: first.published_at.strftime("%Y"),
        month: first.published_at.strftime("%B"),
        published: 1
      },
      {
        year: second.published_at.strftime("%Y"),
        month: second.published_at.strftime("%B"),
        published: 1
      }]
      ).to match_array(archives)
  end
end

但是我收到以下错误

expected collection contained:  [#<Post id: nil>, #<Post id: nil>]
actual collection contained:    [{:year=>"2017", :month=>"October", :published=>1}, {:year=>"2017", :month=>"September", :total=>1}]
the missing elements were:      [#<Post id: nil>, #<Post id: nil>]
the extra elements were:        [{:year=>"2017", :month=>"October", :total=>1}, {:year=>"2017", :month=>"September", :total=>1}]

所以虽然我创建了2个工厂,但是archives数组是空的。我做错了什么?

实际数组不为空,它是两个未设置 id 的 Post 实例的数组(因为 .archives 方法中的 Select 不包含 id 字段)。 您可以不将预期的哈希值与 archives 进行比较,而是将其与类似的东西进行比较:

actual = Post.archives().map do |post| 
  { year: post["year"].to_s, month: post["month"], published: post["total"] }
end

expected = [{
  year: first.published_at.strftime("%Y").to_s,
  month: first.published_at.strftime("%B"),
  published: 1
},
{
  year: second.published_at.strftime("%Y").to_s,
  month: second.published_at.strftime("%B"),
  published: 1
}]

expect(actual).to match_array(expected)

Rspec 标准是使用 let 语法在上下文或描述块中定义变量。测试应如下所示:

describe '.archives' do
  let!(:first) { FactoryGirl.create(:post, published_at: Time.zone.now) }
  let!(:second) { FactoryGirl.create(:post, published_at: 1.month.ago) }

  it 'returns year, month, and total for articles archived' do
    actual_attributes = Post.archives.map { |post| [post.year, post.month, post.total] }
    expected_total = 1 # I don't know why the query is returning 1 for total, but including this for completeness
    expected_attributes = [first, second].map { |post| [post.created_at.year, post.created_at.strftime("%B"), expected_total] }

    expect(actual_attributes).to match_array(expected_attributes)
  end
end

这里的问题是您正在比较仅包含少数属性的记录(SQL 查询的结果)与完整格式的记录(由您的测试创建)。此测试从两组中提取适用的属性并进行比较。