如何让带有枚举字段类型的模型通过规范测试 - Mongoid

4

编辑:根据@max的建议,我将我的模型更改为使用枚举类型,但是我无法测试其默认状态:

it { is_expected.to validate_inclusion_of(:status).to_allow("draft", "published") }

以下模型代码可以正常运行:

validates :status,        :inclusion => { :in => ["draft", "published"] }

但是这部分仍然失败:
it { is_expected.to have_field(:status).with_default_value_of("draft") }

请注意,我正在使用Mongoid。我的模型规范中有以下内容:

旧问题-仅供参考?

it { is_expected.to have_field(:published).of_type(Boolean).with_default_value_of(false) }

在我的模型中,我有这个:

field :published,         type: Mongoid::Boolean,     default: false

然而它并没有起作用。我尝试删除Mongoid部分,但是仍然出现相同的错误:

失败/错误:it { is_expected.to have_field(:published).of_type(Boolean).with_default_value_of(false) } 预期Post具有名为“published”的Boolean类型字段,其默认值为false,但实际上得到的是类型为Mongoid::Boolean的字段“published”

注意:我也尝试过:

field :published,         type: Boolean,     default: false

我在我的模型中添加了以下方法:

after_initialize :set_published, :if => :new_record?

那么

private
def set_published
  self.published ||= false
end

但是似乎什么都没有起作用,我错过了什么吗?

我已经更新了我的回答。 - vmarquet
2个回答

2
class Article
  include Mongoid::Document
  field :published, type: Boolean, default: false
end

require 'rails_helper'

RSpec.describe Article, type: :model do
  it { is_expected.to have_field(:published)
                      .of_type(Mongoid::Boolean)
                      .with_default_value_of(false) }
end

mongoid (4.0.2)mongoid-rspec (2.1.0) 上都可以完美通过。

但是,实际上,在模型状态中使用布尔值并不是最优选择。

如果你考虑一个博客文章或者新闻报道,它可能会是:

 1. draft
 2. published
 3. deleted
 4. ... 

在模型中添加N个开关很繁琐,一个好的解决方案是使用枚举。

首先编写规范:

RSpec.describe Article, type: :model do

  specify 'the default status of an article should be :draft' do
    expect(subject.status).to eq :draft
  end

  # or with rspec-its
  # its(:status) { should eq :draft }
end

然后在你的Gemfile中添加gem "mongoid-enum"

最后添加枚举字段:

class Article
  include Mongoid::Document
  include Mongoid::Enum
  enum :status, [:draft, :published]
end

枚举类型带来了以下所有的优点:

Article.published # Scope to get all published articles
article.published? # Interrogation methods for each state.
article.published! # sets the status

Shoulda-matchers为ActiveRecord枚举提供了it { should define_enum_for :status }匹配器,但我不知道是否存在类似的东西适用于Mongoid。 - max
我理解你的意思并已经更改了代码以使用枚举。感谢你的建议!唯一的问题是我找不到如何测试默认状态。 - WagnerMatosUK
1
上面的测试检查默认状态是否为草稿。您也可以执行类似于 expect(Article.new.draft?).to be_truthy 的操作,以避免显式使用主题。 - max
成功了(it { expect(Article.new.draft?).to be_truthy })谢谢! - WagnerMatosUK

2

如果我理解正确,您在模型中尝试了Mongoid::BooleanBoolean,但没有在测试中尝试。

根据测试失败的消息,我认为应该是:

it { is_expected.to have_field(:published).of_type(Mongoid::Boolean).with_default_value_of(false) }

(在你的模型中添加 field :published, type: Mongoid::Boolean, default: false )

第二个问题:

你知道吗,have_field 是用来测试视图(生成的 HTML),而不是检查字段是否存在于数据库中?

如果没有你的视图代码,我们无法帮助你。

要检查默认值是否为draft,我不知道有任何内置的 Rails 测试方法,所以你应该手动完成。首先创建一个新的模型实例,保存它,然后检查 published 字段是否具有 draft 值。

我不熟悉 Rspec 和你正在使用的语法,但应该类似于(假设你的模型名为Post):

before {
    @post = Post.new
    # some initialization code if needed
    @post.save
}
expect(@post.published).to be("draft")

嘿@vmarquet,你的回答是正确的,但max建议似乎更有道理。无论如何,感谢您的帮助! - WagnerMatosUK
我不知道,只是想测试带有published属性的模型是否具有默认值draft。 我该怎么做呢? PS:我对Rspec和TDD仍然是新手。谢谢! - WagnerMatosUK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接