Ruby on Rails教程第3版,第11章,练习3,测试图像上传器

时间:2015-03-06 10:11:48

标签: railstutorial.org

说明是这样的:

按照清单11.68中的模板,在第11.4节中编写一个图像上传器的测试。作为准备,您应该将图像添加到fixtures目录(使用,例如,cp app / assets / images / rails.png test / fixtures /)。 (如果您正在使用Git,我还建议您更新.gitignore文件,如清单11.69所示。)为了避免混淆错误,您还需要配置CarrierWave以通过创建初始化文件来跳过测试中的图像大小调整,如图所示代码清单11.70清单11.68中的附加断言检查主页上的文件上载字段和有效提交产生的​​微博上的有效图像属性。请注意使用特殊的fixture_file_upload方法将文件作为fixture内的夹具上传.2提示:要检查有效的图片属性,请使用第10.1.4节中提到的assigns方法在有效提交后访问创建操作中的微博。< / p>

这是我在test / integration / micrposts_interface_test.rb

中的代码
  test "micropost interface" do
    log_in_as(@user)
    get root_path
    assert_select 'div.pagination'
    assert_select 'input[type=FILL_IN]'
    # Invalid submission
    assert_no_difference 'Micropost.count' do
      post microposts_path, micropost: { content: "" }
    end
    assert_select 'div#error_explanation'
    # Valid submission
    content = "This micropost really ties the room together"
    picture = fixture_file_upload('test/fixtures/rails.png', 'image/png')
    assert_difference 'Micropost.count', 1 do
      post microposts_path, micropost: { content: content, picture: FILL_IN }
    end
    assert FILL_IN.picture?
    follow_redirect!
    assert_match content, response.body
    # Delete a post.
    assert_select 'a', text: 'delete'
    first_micropost = @user.microposts.paginate(page: 1).first
    assert_difference 'Micropost.count', -1 do
      delete micropost_path(first_micropost)
    end
    # Visit a different user.
    get user_path(users(:archer))
    assert_select 'a', text: 'delete', count: 0
  end

在assert_select'input [type = FILL_IN]'中,我的填写是type = file

在post microposts_path,micropost:{content:content,picture:FILL_IN}中,我的填写是图片:true

断言FILL_IN.picture?是@ user.microposts.picture?

我得到的错误是: NoMethodError:NoMethodError:未定义的方法`picture?'对于#

所以我认为我的前两个FILL_IN是正确的。问题来自第三次填写。我写了@ user.microposts因为我想测试图片的存在吗?它必须在用户的微博上。但这个错误不是图片的方法吗?

我也试过了@ user.micropost.picture ?,错误是NoMethodError:NoMethodError:未定义的方法`micropost'代表#

我认为我的推理线是正确的,但显然不是。救命!我是一个完整的新手。

4 个答案:

答案 0 :(得分:4)

我的解决方案,似乎有效:

test "micropost interface" do
  log_in_as(@user)
  get root_path
  assert_select 'div.pagination'
  assert_select 'input[type=file]'
  # Invalid submission
  assert_no_difference 'Micropost.count' do
    post microposts_path, micropost: { content: "" }
  end
  assert_select 'div#error_explanation'
  # Valid submission
  content = "This micropost really ties the room together"
  picture = fixture_file_upload('test/fixtures/sample-image.jpg', 'image/jpg')
  assert_difference 'Micropost.count', 1 do
    post microposts_path, micropost: { content: content, picture: picture }
  end
  assert assigns(:micropost).picture?
  assert_redirected_to root_url
  follow_redirect!
  assert_match content, response.body
  # Delete a post.
  assert_select 'a', text: 'delete'
  first_micropost = @user.microposts.paginate(page: 1).first
  assert_difference 'Micropost.count', -1 do
    delete micropost_path(first_micropost)
  end
  # Visit a different user.
  get user_path(users(:archer))
  assert_select 'a', text: 'delete', count: 0
end

答案 1 :(得分:3)

回答这个问题的时间不多,但也许这会帮助其他人。我为每个人提供了长短的答案,如果你想要快速解释,请在问题的最后阅读TLDR,如果你想要更多的解释,请随时阅读:)

1)assert_select&#39;输入[type = FILL_IN]&#39;

使用任一文件或&#34;文件&#34;将通过测试。根据assert_select的文档:link,&#34;选择器可以是CSS选择器表达式(String),带替换值的表达式,或HTML :: Selector对象。&#34;从本质上讲,它只需要一个有效的CSS选择器,根据这个stackoverflow帖子:link,根据情况而定(如果它是一个字母数字字符串,通常不需要它,就像这里的情况一样,它可能需要也可能不需要引号,但通常使用它们是好的做法,这样就不会出现混淆/错误。

TLDR:使用&#39;输入[type =&#34; file&#34;]&#39;或者&#39;输入[type = file]&#39;在这种情况下会起作用,但使用引号通常被认为是避免错误的好习惯。

2)发布microposts_path,micropost:{content:content,picture:FILL_IN}

对于这个,正如@Nick所提到的,你可能只想使用变量&#39; picture&#39;这是在assert_difference行上方创建的。请记住,当您将图片属性添加到微博模型时,您运行了命令:

rails generate migration add_picture_to_microposts picture:string

这意味着它在创建微博时期望你传递一个字符串,而不是一个布尔值。还要注意测试实际上在做什么:

assert_difference 'Micropost.count', 1 do
    post microposts_path, micropost: { content: content, picture: FILL_IN }
end

代码实际上是通过发布到微博路径创建微博,然后检查以确保计数增加1.

现在,您可能会说:但图片变量不是字符串!这是事实,我不是CarrierWave的专家,我还没有真正挖掘它的代码,但似乎它实际上期待文件路径和MIME(文件扩展名)类型,基于fixture_file_upload的文档,可在此处找到:link。如果您还记得本教程,则添加以下行:

mount_uploader :picture, PictureUploader

到您的微博模型,它似乎将图片属性与PictureUploader类(在app / uploaders / picture_uploader.rb中找到)相关联,该类在类文件中包含以下内容:

class PictureUploader < CarrierWave::Uploader::Base

这意味着它继承自CarrierWave :: Uploader :: Base类,这可能意味着CarrierWave正在使用picture属性来处理除字符串以外的东西(正如我所提到的,它似乎需要一个基于文档的路径和MIME类型),但布尔值不会起作用。 (为了记录,我做了一些测试,传递一个随机字符串,然后传递一个随机文件路径,并且都按预期失败 - 所以传递布尔值也是如此。)

此外,并且无可否认它是一个小细节,但即使传入一个布尔值有效,它通常只会测试它是一张图片,而不是特定的图片,这将是另一个使用图片变量。

TLDR:您应该只使用图片变量:post microposts_path,micropost:{content:content,picture:picture}

3)断言FILL_IN.picture?

你提到你使用过代码:

@user.microposts.picture?

得到NoM​​ethodError。原因是@ user.microposts将返回一个微博集合,而不是单个微博,因此它很混乱(具体来说,它返回一个ActiveRecord_Associations_CollectionProxy,它没有图片?方法,因此,你得到一个NoMethodError另外,不要忘记,您可以打开rails控制台,并运行User.first.microposts.class以找出@ user.microposts返回的对象类型。还记得那张照片吗?方法仅适用于单个微博,因此您需要执行以下操作:

@user.microposts.first.picture?

将检查最近创建的微博(微博按照它们创建的日期/时间排序,最新的是第一个)用于图片。

但是,还有另一种方法可以实现,它使用了Hartl在练习中给出的提示:&#34;要检查有效的图片属性,请使用第10.1.4节中提到的分配方法来访问有效提交后的创建操作中的微博&#34;

如果您还记得,可以使用assignign方法从控制器访问实例变量。微博控制器中的创建动作有一个实例变量@micropost,它也是用户创建的最新微博。

代码如下:

foo = assigns(:micropost)
assert foo.picture?

事实上,您可以通过添加以下代码向自己证明这两种方法都有效:

foo = assigns(:micropost)

assert foo.picture?
assert @user.microposts.first.picture?

assert_equal foo, @user.microposts.first

所以这段代码的作用如下:首先,它创建一个变量foo并为其分配新创建的微博。然后检查foo.picture?是的,然后检查另一个方法,@ user.microposts.first.picture?并检查它是否也是真的。最后,它检查foo和@user的最新微博是否相同,所有这些测试都应该通过。

TLDR:你在说这张照片?微博集​​合的方法,而不是单个微博。你可以使用@ user.microposts.first.picture吗?或者,如果您想使用assigns()方法,您也可以使用它,并使用以下内容:

foo = assigns(:micropost)
assert foo.picture?

希望有所帮助!

答案 2 :(得分:2)

我相信第一个FILL_IN应该读type="file"来检查这样的输入是否可用。

对于第二个FILL_IN,我认为解决方案是{ content: content, picture: picture },其中最后一张&#39;图片&#39;指的是上面两行(你定义这个变量)。

他们和最后一次FILL_IN我不确定。考虑到Hartl提供的暗示,我认为它应该是:

plaatje = assigns(:micropost)
assert plaatje.picture?

但我也是新手并且遵循教程,所以我可能错了。如果有效,请告诉我。

使用这些解决方案,完整代码为:

test "micropost interface" do
  log_in_as(@user)
  get root_path
  assert_select 'div.pagination'
  assert_select 'input[type="file"]'
  # Invalid submission
  assert_no_difference 'Micropost.count' do
    post microposts_path, micropost: { content: "" }
  end
  assert_select 'div#error_explanation'
  # Valid submission
  content = "This micropost really ties the room together"
  pict = fixture_file_upload('test/fixtures/rails.png', 'image/png')
  assert_difference 'Micropost.count', 1 do
    post microposts_path, micropost: { content: content, picture: pict }
  end
  plaatje = assigns(:micropost)
  assert plaatje.picture?
  assert_redirected_to root_url
  follow_redirect!
  assert_match content, response.body
  # Delete a post.
  assert_select 'a', text: 'delete'
  first_micropost = @user.microposts.paginate(page: 1).first
  assert_difference 'Micropost.count', -1 do
    delete micropost_path(first_micropost)
  end
  # Visit a different user.
  get user_path(users(:archer))
  assert_select 'a', text: 'delete', count: 0
end

答案 3 :(得分:0)

第三个FILL_IN实际上可以使用以下方式填写:     @ user.microposts.first.picture? 您的第一个解决方案不起作用,因为您必须指定要查询的微博。