Question

New to both Ruby and Rails, working on an app using Test::Unit. I come from a background in PHP and PHPUnit, where they provide formal structure for data providers: you define a nested array/hash of arguments in one method, then loop a single test through it, swapping the arguments on each pass. It's a concise way to repeatedly test the the same event with different parameters.

The only solution I have found thus far is to replicate the concept manually, inside a single test:

test "should properly do something" do
  provider = [
    {:var1 => 'foo',     :var2 => 'bar', :expected => true},
    {:var1 => 'foo',     :var2 => 'baz', :expected => true},
    {:var1 => 'invalid', :var2 => 'bar', :expected => false},
    # ...
  ]
  provider.each do |t|
    assert_equal(t.expected, SomeObject.some_method(t.var1, t.var2))
  end
end

This doesn't give me as much useful test output, since it can't discern which loop actually fails in the event of an error.

Is there a better way to do this?

Was it helpful?

Solution

You could just reformat your test code like so:

[
  ['foo',     'bar', true ],
  ['foo',     'baz', true ],
  ['invalid', 'bar', false],
  # …
].each do |v1, v2, expected|
  test "expecting #{expected} with #{v1} and #{v2}" do
    assert_equal(expected, SomeObject.some_method(v1, v2))
  end
end

However, with Rails I find a combination of RSpec, FactoryGirl and Faker/ffaker easier to use. I also don't create a “data provider” and test against this matrix, but specify the behaviour (whether it is Test::Unit or RSpec), like so:

test "expecting positive result" do
  assert SomeObject.some_method('foo', 'bar')
  assert SomeObject.some_method('foo', 'baz')
  # …
end

test "expecting negative result" do
  assert_false SomeObject.some_method('invalid', 'baz')
  # …
end

or (RSpec):

require 'spec_helper'

describe SomeObject do
  describe '#some_method' do
    specify "positive result" do
      expect(SomeObject.some_method 'foo', 'bar').to be true
      expect(SomeObject.some_method 'foo', 'baz').to be true
      # …
    end

    specify "negative result" do
      expect(SomeObject.some_method 'invalid', 'bar').to be false
      # …
    end
  end
end

OTHER TIPS

I also have this problem, I like to avoid repeating logic when the only thing that changes is that data. You can however send a string to Unit::Test assertions, so you can just store your string in the array.

The inconvenience I find in this is that as soon as a test fails, the others wont run. Also since ruby doesn't allow lines to start with commas, I can't just comment out a test temporarily, but that is another problem all together.

def testMergeNestedHash

    data =
    [
            [
                  "merge two empty hashes, shourd return empty hash"                      \
                , {}                                                                      \
                , {}                                                                      \
                , {}                                                                      \
            ]                                                                             \
                                                                                          \
        ,   [                                                                             \
                  "a simple nested merge"                                                 \
                , { a: { b: 'one', c: 'two'             } }                               \
                , { a: { e: 'three'                     } }                               \
                , { a: { b: 'one', c: 'two', e: 'three' } }                               \
            ]                                                                             \
                                                                                          \
        ,   [                                                                             \
                  "override an existing non-hash element"                                 \
                , { a: { b: 'one' , c: 'two'             } }                              \
                , { a: { b: 'four', e: 'three'           } }                              \
                , { a: { b: 'four', c: 'two', e: 'three' } }                              \
            ]                                                                             \
    ]


    data.each do | arr |

        assert_equal( arr[ 3 ], arr[ 1 ].recursive_merge!( arr[ 2 ] ), "\n\nTEST: " + arr[ 0 ] + "\n" )

    end

end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top