Michael Hartl Rails教程:assert_not与它应该完全相反,我不明白为什么

时间:2015-09-03 04:47:29

标签: ruby-on-rails ruby validation tdd assertions

tl; dr有效名称不会写入数据库,因为测试失败,并且因为测试通过而无效的名称会写入数据库。

编辑: 有关项目和我的问题的一般说明:如本书所述,此用户模型设置为允许网站用户最终登录的开始阶段进入一个网站。数据库列将是" name"和"电子邮件",每行将是一个用户(假设用户名和电子邮件有效)。我已编辑了以下原始帖子以进一步说明,所有修改均以斜体显示。

此外,如果您可以在我的帖子中解释代码 ,请回复 - 请勿建议添加其他代码以使其正常工作。我工作的教科书声称这段代码应该按原样运行,但它似乎正在评估它应该相反的情况。最后,如果您知道其他链接可以更详细地解释这一点,那么这很有帮助;但是,我已经阅读了apidockRoR API以及Google搜索中显示的大部分SO链接,但没有任何内容有助于解释此问题。

我正在完成Michael Hartl的Ruby on Rails教程。我在第6章中进行了验证测试,并且我坚持验证是否存在名称。它似乎与教程应该做的完全相反(即,验证无效的名称条目),即使我完全按照教程。我还在网上搜索了SO以获取有关assert_not工作原理的详细信息,但无法找到任何有用的详细信息。这是我经历过的过程。

  1. 添加我们知道会失败的测试:

    require 'test_helper'
    
    class UserTest < ActiveSupport::TestCase
    
      def setup
        @user = User.new(name: "Example User", email: "user@example.com")
      end
    
      # resolves to true and passes
      test "should be valid" do
       assert @user.valid?
      end
    
      test "name should be present" do
        @user.name = "     "
        assert_not @user.valid?
      end
    
    end
    
  2. 到目前为止一切顺利。我完全理解这段代码,虽然第二次测试的措辞很尴尬,但我将assert_not @user.valid?解释为这样:@user.valid?求值为true,因为没有设置验证,所以测试认为所有空格的名称都是有效的。这之前是assert_not,它将true值转换为false,并使测试失败。

    1. 我们添加了验证测试:

      class User < ActiveRecord::Base
        validates :name, presence: true
      end
      
    2. 这为User模型设置了一个验证规则,确保:name对象具有内容且不是nil,空字符串或空格。到目前为止仍然很好。

      1. 这里的事情变得棘手。此时,我们测试中的表达式@user.valid?应该(并且确实)评估为false,因为验证规则不允许:name仅包含空格。我已经在此代码旁边添加了评论,以帮助我了解在此过程中分配和评估的值:

        test "name should be present" do
            @user.name = "   "
            # => name: "   " email: "example@example.com"
            assert_not @user.valid? 
            # => assert_not false => true
        end
        
      2. @user.valid?计算结果为false,这使得整个assert_not表达式求值为true,从而测试通过。 在伪代码中,这一行可以这样翻译:{{1​​}} ==&gt; assert_not (is the user valid? no) ==&gt; assert_not(false)。类似地,&#34;我们没有断言用户是假的&#34;,其评估为真。

        这就是我的问题所在:测试传递了true的无效值,因此允许将包含空格的名称写入数据库,而这恰好与我们正在尝试实现,即阻止将空白名称写入db。

        1. 相反,我用有效名称计算了这个逻辑:

          :name
        2. 在这种情况下,由于test "name should be present" do # => name: "Example User" email: "example@example.com" assert_not @user.valid? # assert_not true => false end 的计算结果为true(因为&#34;示例用户&#34;是有效名称),@user.valid?计算结果为false,测试失败,并且我们的有效名称没有写入数据库。 在伪代码中,这一行可以这样翻译:{{1​​}} ==&gt; assert_not @user.valid? ==&gt; assert_not (is the user valid? yes)。类似地,&#34;我们没有声明用户是真的&#34;,其评估为false。由于测试评估为false(即使使用真实/有效的用户名),因此不会将此有效名称写入数据库。

          如果有人可以解释这有什么意义,我会非常感激,并且详细解答让我走过它会更好。

3 个答案:

答案 0 :(得分:3)

  

测试传递的值无效   :name,因此允许写入由空格组成的名称   到数据库...

如果后面的表达式@user.valid?返回false,则

assert_not返回true(与测试传递相同)。实际上,第3节中的测试说:我们并未断言用户是有效的。由于该期望/断言是正确的,它返回true并且测试通过。没有任何东西保存到数据库中。

答案 1 :(得分:0)

您可以在添加字符串时添加验证&#34; &#34;包含两个空格

  class User < ActiveRecord::Base
   validates :name, presence: true, allow_blank: false
   validate :name_of_valid

   def name_of_valid
    self.errors.add :base, 'My string can not be empty' if self.name == "   " 
   end
end

然后

test "name should be present" do
    @user.name = "   "
    # => name: "   " email: "example@example.com"
    assert_not @user.valid? 
    # => assert_not true 
end

答案 2 :(得分:0)

我有同样的问题。仅对于presence: true,测试失败,当我添加allow_blank: false时,测试通过。