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 为此。