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

问题描述 投票:4回答:3

tl; dr因为测试失败,所以未将有效名称写入数据库,而由于测试通过,因此无效名称也已写入数据库。

编辑: 为了澄清项目和我的一般问题:如书中所述,此用户模型被设置为开始阶段,以允许网站用户最终登录到网站。数据库列将是“名称”和“电子邮件”,并且每一行将是一个用户(假设用户名和电子邮件有效)。为了进一步澄清,我已经编辑了我的原始帖子,所有编辑均以斜体显示。

此外,仅当您可以在我的帖子中解释代码原样时,请回复-不要建议添加其他代码以使其正常工作。我正在使用的教科书断言该代码应按原样工作,但似乎却得出相反的结论。最后,如果您知道其他链接可以更详细地说明这一点,则很有帮助;但是,我已经阅读了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: "[email protected]")
      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
    

到目前为止很好。我很好地理解了这段代码,尽管第二个测试的措词很尴尬,但我认为assert_not @user.valid?的工作方式如下:@user.valid?计算为true,因为未设置任何验证,因此该测试认为名称全为空白空格有效。这之前是一个assert_not,它将真实值转换为false,并使测试失败。

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

    class User < ActiveRecord::Base
      validates :name, presence: true
    end
    

这将为用户模型设置一个验证规则,以确保:name对象具有内容且不为nil,空字符串或空格。到目前为止还不错。

  1. 这是棘手的地方。在这一点上,我们的测试中的表达式@user.valid?应该(并且确实)求值为false,因为验证规则不允许其中仅包含空格的:name。我在此代码旁边添加了注释,以帮助我了解在此过程中分配和评估的值:

    test "name should be present" do
        @user.name = "   "
        # => name: "   " email: "[email protected]"
        assert_not @user.valid? 
        # => assert_not false => true
    end
    

@user.valid?的计算结果为false,这使整个assert_not表达式的计算结果为true,因此测试通过。 在伪代码中,此行可以这样翻译:assert_not (is the user valid? no) ==>assert_not(false)==> true。同样,“我们不断言用户为假”,其结果为true。

这是我的问题所在:测试传递了:name的无效值,因此允许将由空格组成的名称写入数据库,而这与我们要实现的目的恰好相反,即,preventing空白名称不会写入数据库。

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

    test "name should be present" do
    # => name: "Example User" email: "[email protected]"
        assert_not @user.valid? 
        # assert_not true => false
    end
    

在这种情况下,由于@user.valid?的值为true(因为“ Example User”是有效名称),所以assert_not @user.valid?的值为false,测试失败,并且我们的有效名称未写入数据库。 在伪代码中,此行可以这样翻译:assert_not (is the user valid? yes) ==>assert_not(true)==> false。同样,“我们不会断言用户为真”,其结果为false。因为测试的结果为false(即使使用正确的用户名也是如此),所以不会将此有效名称写入数据库。

[如果有人可以解释这有什么意义,我将不胜感激,详细的答案会更好地指导我。

ruby-on-rails ruby validation tdd assertions
3个回答
4
投票

测试通过了一个无效的值:name,因此允许写入由空格组成的名称到数据库...

如果后面的表达式assert_not返回false,则

@user.valid?返回true(与测试通过相同)。实际上,第3节中的测试说:我们并不是在断言该用户有效。由于该期望/断言是正确的,因此它返回true,并且测试通过。什么都没有保存到数据库。


0
投票

您可以在添加字符串“”时包含两个空格的同时添加验证

  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: "[email protected]"
    assert_not @user.valid? 
    # => assert_not true 
end

0
投票

我有同样的问题。仅在使用presence: true时测试失败,并且当我添加allow_blank: false时测试通过。

© www.soinside.com 2019 - 2024. All rights reserved.