Rspec 控制器测试因撇号字符而失败?
Rspec controller test failing with Apostrophe Character?
现在我有使用"Faker"公司名称的单元测试失败。
expect(response.body).to match(@thing.name)
好像搞砸了。
查看错误时,Faker公司名称有时会出现"O'Brian Company"或"O'Hare Company"或类似的内容。
faker是编码字符串吗?因为我知道匹配编码字符串不是一个好主意,而且我真的不想在我使用的 Factory 中指定一个特定的公司名称。
谢谢
您可以尝试使用#include 而不是使用#match。
expect(response.body).to include(@thing.name)
您可以尝试传递正则表达式而不是字符串:
expect(response.body).to match(Regexp.new(@thing.name))
此外,如果问题只是在你从 faker 那里得到这种类型的名字时,那么你应该看看这个 ,它提供了一些很好的见解。
Faker 不会为你做任何编码。它只会给你一个像 O'Malley
这样的字符串。但响应应该有 HTML 转义(或其他类型,取决于格式),如 O'Malley
。你总是可以 puts response.body
来确定。
RSpec matches
匹配器是真正设计的 for either expected
or actual
to be a regular expression, but in your case both are strings. Because the code has an optimization calling values_match?
which does a simple comparison,你实际上是在说 expect(response.body).to eq(@thing.name)
.
如果您确实需要正则表达式,那么在创建它时应小心使用不受控制的值是正确的。幸运的是 Ruby 有 Regexp.escape
,所以你可以说 Regexp.new("foo" + Regexp.escape(@thing.name) + "bar")
。但是从您对 include
的反对来看,听起来您实际上希望响应只包含名称,对吗?在这种情况下,您根本不需要正则表达式。
无论如何,问题不在于名称周围是什么,而是名称如何转义。因此,在比较之前,您应该 (1) 解码响应或 (2) 编码 faker 字符串。哪个并不重要。两者都很简单:
expect(CGI.unescapeHTML(response.body)).to eq @thing.name
或
expect(response.body).to eq CGI.escapeHTML(@thing.name)
当然,如果您的回答是 JSON,您应该将所有这些 HTML 转义内容替换为 JSON,等等
假设您指的是 Faker::Company of the Faker gem
使您的示例期望通过的正确方法是像 @rafael-costa 示例中那样使用 Regexp
。这样做可以避免撇号之类的东西。
使用 Faker 的问题是你的测试不是确定性的。最好的做法是为您的测试提供静态的、已知的输入,并期望输出能够通过基于这些输入的特定预期。如果没有更多信息,很难提供相关示例,但可能是这样的:
company = Company.new(name: 'Acme Anvils')
get :show, params: {id: company.to_param}, session: {}
expect(response.body).to match(Regexp.new('Acme Anvils', Regexp::MULTILINE))
此外,您通常不应测试控制器规格中的特定 body 输出。这样做就是跨目的测试。你通常会 write a view
test 为此。
现在我有使用"Faker"公司名称的单元测试失败。
expect(response.body).to match(@thing.name)
好像搞砸了。
查看错误时,Faker公司名称有时会出现"O'Brian Company"或"O'Hare Company"或类似的内容。
faker是编码字符串吗?因为我知道匹配编码字符串不是一个好主意,而且我真的不想在我使用的 Factory 中指定一个特定的公司名称。
谢谢
您可以尝试使用#include 而不是使用#match。
expect(response.body).to include(@thing.name)
您可以尝试传递正则表达式而不是字符串:
expect(response.body).to match(Regexp.new(@thing.name))
此外,如果问题只是在你从 faker 那里得到这种类型的名字时,那么你应该看看这个
Faker 不会为你做任何编码。它只会给你一个像 O'Malley
这样的字符串。但响应应该有 HTML 转义(或其他类型,取决于格式),如 O'Malley
。你总是可以 puts response.body
来确定。
RSpec matches
匹配器是真正设计的 for either expected
or actual
to be a regular expression, but in your case both are strings. Because the code has an optimization calling values_match?
which does a simple comparison,你实际上是在说 expect(response.body).to eq(@thing.name)
.
如果您确实需要正则表达式,那么在创建它时应小心使用不受控制的值是正确的。幸运的是 Ruby 有 Regexp.escape
,所以你可以说 Regexp.new("foo" + Regexp.escape(@thing.name) + "bar")
。但是从您对 include
的反对来看,听起来您实际上希望响应只包含名称,对吗?在这种情况下,您根本不需要正则表达式。
无论如何,问题不在于名称周围是什么,而是名称如何转义。因此,在比较之前,您应该 (1) 解码响应或 (2) 编码 faker 字符串。哪个并不重要。两者都很简单:
expect(CGI.unescapeHTML(response.body)).to eq @thing.name
或
expect(response.body).to eq CGI.escapeHTML(@thing.name)
当然,如果您的回答是 JSON,您应该将所有这些 HTML 转义内容替换为 JSON,等等
假设您指的是 Faker::Company of the Faker gem
使您的示例期望通过的正确方法是像 @rafael-costa 示例中那样使用 Regexp
。这样做可以避免撇号之类的东西。
使用 Faker 的问题是你的测试不是确定性的。最好的做法是为您的测试提供静态的、已知的输入,并期望输出能够通过基于这些输入的特定预期。如果没有更多信息,很难提供相关示例,但可能是这样的:
company = Company.new(name: 'Acme Anvils')
get :show, params: {id: company.to_param}, session: {}
expect(response.body).to match(Regexp.new('Acme Anvils', Regexp::MULTILINE))
此外,您通常不应测试控制器规格中的特定 body 输出。这样做就是跨目的测试。你通常会 write a view
test 为此。