4

Ruby で 1 つのクラスの 2 つのインスタンスの同一性を単体テストしようとしています。

def test_example
    a = Object.new
    b = Object.new

    assert_equal a, b
end

インスタンスはそれぞれ独自のメモリポインターを持つ個別の変数であるため、これが失敗することを理解しています。私が求めているのは、インスタンスが参照ポインター以外のすべての点で同一である場合に、このテストに合格することです。

より複雑な (不自然な場合) 例を次に示します。

# Let's stir up something...
class FooBar
    attr_accessor :seed, :foo, :bar

    def foo_the_bar()
        @bar = @seed + @foo * 3
    end
end

f = FooBar.new
f.seed = "Mountains "
f.foo  = "are just mountains "
f.bar = "obliterate me!"
f.foo_the_bar
p f.bar # "Mountains are just mountains are just mountains are just mountains "


# So far so good, now let's test if one FooBar is same as another...

require 'test/unit'
class FooBarTest < Test::Unit::TestCase

    # Test fails: <#<FooBar:0x9a40d18>> expected but was <#<FooBar:0x9a40d04>>.
    # But what we really want is a way to make this pass
    # since the objects are exactly the same in every respect,
    # besides their pointers.
    def test_foobar_1_init
        f1 = FooBar.new
        f2 = FooBar.new

        assert_equal f1, f2
    end

    # Again, test fails, but we want it to pass,
    # since the instance variables are the same.
    def test_foobar_2_instance_var
        f1 = FooBar.new
        f2 = FooBar.new

        f1.seed = "Santa says "
        f1.foo = "ho "
        f1.bar = "something"
        f1.foo_the_bar

        f2.seed = f1.seed
        f2.foo = f1.foo
        f2.foo_the_bar

        assert_equal f1, f2
    end

    # This test fails for the wrong reason.
    # We want this to fail because the instance variables are different.
    # This test should also fail if we add a method to one of the instances,
    # or make the instances differ from each some other way.
    def test_foobar_3_diff
        f1 = FooBar.new
        f2 = FooBar.new

        f1.seed = "Kitty goes "
        f1.foo = "meow "
        f1.foo_the_bar

        f2.seed = "Doggies goes "
        f2.foo = "woof "
        f2.foo_the_bar

        assert_equal f1, f2
    end
end
4

3 に答える 3

1

メソッドを定義するだけFooBar#==です:

class FooBar
  def ==(other)
    [bar, seed, foo] == [other.bar, other.seed, other.foo]
  end
end

今すぐ合格し、正しい理由でtest_foobar_1_init失敗します。test_foobar_2_instance_vartest_foobar_3_diff

欠点は、オブジェクト構造を変更する場合、==それに応じてメソッドを変更する必要があることです。

于 2012-10-31T08:51:49.630 に答える
1
f1.attributes.keys.collect(&:to_sym).each do |field|
 assert_equal f1.send(field), f2.send(field)
end

これにより、すべてのフィールドが等しいことがアサートされます。しかし、欠点はアサーションの数です。それが発生したくない場合は、このようにオブジェクトにIDを割り当てます

f1.id = 1
f2.id = 1 
assert_equal f1, f2

ただし、不整合につながる可能性があるオブジェクトは保存しないでください。

于 2012-10-31T08:23:01.873 に答える
-1

apidockのソースによると、 assert_equals は最初にメソッドを使用してオブジェクトを文字列に変換しますinspect。の inspect メソッドを定義する必要があります。class FooBar

class FooBar
  def inspect
    # create a unique string of attributes here, maybe a json string.
  end
end
于 2012-10-31T08:40:19.613 に答える