テストコード: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」を使用するのもいいと思います。