test-unit、Minitest、Rails の refute / assert_not エラーメッセージを比較

masuyama13.hatenablog.com

昨日上の記事を書いたが、今度は test-unit の refute のコードとエラーメッセージはどうなっているんだろうと気になって調べてみた。

test-unit で失敗するテストを書く

blog.rb

class Blog
end

blog_unit_test.rb

require "test/unit"
require "./blog"

class FizzbuzzTest < Test::Unit::TestCase
  test "Blogクラスのオブジェクトを作れない" do
    refute Blog.new
  end
end

refute A:Aが偽であればパスする。

Blog.newtrueになるはずなので、テストは失敗する。

実行結果

$ ruby blog_unit_test.rb
Loaded suite blog_unit_test
Started
F
=========================================================================
     3: 
     4: class BlogTest < Test::Unit::TestCase
     5:   test "Blogクラスのオブジェクトを作れない" do
  => 6:     refute Blog.new
     7:   end
     8: end
blog_unit_test.rb:6:in `block in <class:BlogTest>'
Failure: test: Blogクラスのオブジェクトを作れない(BlogTest): <#<Blog:0x00007f973c845ff0>> is neither nil or false.
=========================================================================

Finished in 0.005049 seconds.
-------------------------------------------------------------------------
1 tests, 1 assertions, 1 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
0% passed
-------------------------------------------------------------------------
198.06 tests/s, 198.06 assertions/s

refuteのエラーメッセージ

Failure: test: Blogクラスのオブジェクトを作れない(BlogTest): <#<Blog:0x00007f973c845ff0>> is neither nil or false.

test-unit refuteメソッドのコード

# Asserts that `object` is false or nil.
#
# @note Just for minitest compatibility. :<
#
# @param [Object] object The object to be asserted.
# @return [void]
#
# @example Pass patterns
#   refute(false)    # => pass
#   refute(nil)      # => pass
#
# @example Failure patterns
#   refute(true)     # => failure
#   refute("string") # => failure
#
# @since 2.5.3
def refute(object, message=nil)
  _wrap_assertion do
    assertion_message = nil
    case message
    when nil, String, Proc
    when AssertionMessage
      assertion_message = message
    else
      error_message = "assertion message must be String, Proc or "
      error_message += "#{AssertionMessage}: "
      error_message += "<#{message.inspect}>(<#{message.class}>)"
      raise ArgumentError, error_message, filter_backtrace(caller)
    end
    assert_block("refute should not be called with a block.") do
      !block_given?
    end
    assertion_message ||= build_message(message,
                                        "<?> is neither nil or false.",
                                        object)
    assert_block(assertion_message) do
      not object
    end
  end
end

test-unit/assertions.rb at master · test-unit/test-unit · GitHub

test-unit、Minitest、ActiveSupport (Rails) の比較

コードは、Minitest と ActiveSupport の2つに比べると複雑。エラーメッセージも異なることがわかった。

コメントに、Just for minitest compatibility.とある。

Minitest 互換性のためだけです。

互換性のためだけなのに、エラーメッセージ変えた??

(参考)

Minitest refute メソッドのコード(Minitest)

  def refute test, msg = nil
    msg ||= message { "Expected #{mu_pp(test)} to not be truthy" }
    assert !test, msg
  end

minitest/assertions.rb at master · seattlerb/minitest · GitHub

ActiveSupportRailsassert_not メソッドのコード

  def assert_not(object, message = nil)
    message ||= "Expected #{mu_pp(object)} to be nil or false"
    assert !object, message
  end

rails/assertions.rb at 77932446895bd70f38a3aaa1ab288bf8a7b7142c · rails/rails · GitHub

エラーメッセージ

英語だしそれほど変わらないように見えるが、エラーメッセージを変えるためにわざわざassert_notは別で定義されているくらいなので、ここは結構大事なのかもしれない。DeepL さんの力を借りつつ、できるだけニュアンスが伝わるように訳してみる。

test-unit refuteのエラーメッセージ

<#<Blog:0x00007f973c845ff0>> is neither nil or false.

オブジェクトは nil でも false でもありません。

Minitest refuteのエラーメッセージ

Expected #<Blog:0x00007f9da82c2a20> to not be truthy.

オブジェクトは truthy でないことが期待されています。

ActiveSupportRailsassert_notのエラーメッセージ

Expected #<Blog:0x00007f9da82c1440> to be nil or false

オブジェクトは nil または false であることが期待されています

まとめ

日本語にするとあまり違いがわからない…汗

ところで今まで頑張って見えないフリをしてきたtruthyってどういう意味??一昨日の記事に書いたこれ↓

ActiveSuppert assert_not コード上のコメント

Asserts that an expression is not truthy. Passes if object is nil or false. "Truthy" means "considered true in a conditional" like if foo.

表現が truthy ではないことを主張します。オブジェクトが nil か false の場合にパスするのです。"truthy" は if foo のように "条件付きで true とみなされる" ことを意味します。

rails/assertions.rb at 77932446895bd70f38a3aaa1ab288bf8a7b7142c · rails/rails · GitHub

もう一回調べよう。(続く)