テストコード:product.errors[:price].join(';')
モデルのテストコードの中で次のような検証を行うところがあります。
product.price = -1
assert product.invalid?
assert_equal "must be greater than or equal to 0.01",
product.errors[:price].join(';')
上記コードは、productのpriceに-1を設定して、不正であることを検証しています。
その後にエラーメッセージを検証しています。
エラーメッセージはarrayなので"join()"しているようですが、期待する値に";"がないのに、なぜ"join(;)"しているのか調べてみました。
結果を先に記載しておくと、要素が1つのarrayに"join(";")"を実行すると区切り文字が無い形で1つ目の要素が取得されるようです。
以下、arrayの動作検証がメインになっていますがいくつかのパターンを検証してみました。
◆検証1
product.price = -1
assert product.invalid?
assert_equal "must be greater than or equal to 0.01",
product.errors[:price].join(';')
もちろん検証はPassします。
◆検証2
product.price = -1
assert product.invalid?
assert_equal "must be greater than or equal to 0.01",
product.errors[:price].join
こちらも検証はPassします。
◆検証3
product.price = -1
assert product.invalid?
assert_equal "must be greater than or equal to 0.01",
product.errors[:price].to_s
検証はFailで次の結果が返ってきます。
--- expected
+++ actual
@@ -1 +1 @@
-"must be greater than or equal to 0.01"
+"[\"must be greater than or equal to 0.01\"]"
調べて見ると、arrayの".to_s"を実行するとすべての要素が"\"で区切られた文字列が取得できるようです。
irb(main):003:0> x = ["ABC"]
=> ["ABC"]
irb(main):004:0> x.to_s
=> "[\"ABC\"]"
irb(main):005:0> y = ["A","B","C"]
=> ["A", "B", "C"]
irb(main):006:0> y.to_s
=> "[\"A\", \"B\", \"C\"]"
◆検証4
product.price = -1
assert product.invalid?
assert_equal "must be greater than or equal to 0.01",
product.errors[:price][0].to_s
こちらもPassします。ただし、こちらのケースは次のようなリスクもあります。
- エラーメッセージが1件であることも検証したい場合、このテストコードでは検証できない。
- 複数のエラーメッセージが出力されるように変更になった場合、テストコードが意図した動きをせず、テストコードの破損に気付けない。
個人的には「検証2」の方法が余計な情報を含んでいなくていいと思います。
arrayのjoinを引数なしで実行するとこうなります。
irb(main):005:0> y = ["A","B","C"]
=> ["A", "B", "C"]
irb(main):006:0> y.join
=> "ABC"
もしくは、エラーメッセージの配列が1件であることを検証した後に「検証4」を使用するのもいいと思います。