3

What's the best way to test methods like the following using mocha gem?

def can_create?(user)
  opened? && (owner?(user) || member?(user))
end

Is a best practice to test "AND" and "OR" conditions? Should I create many tests to cover all possibilities or one expects options to cover all?


I'm using rails 4 + test unit.

When i have tests only with &&, for instance:

def can_update?(user)
  opened? && owner?(user)
end

I'm testing:

group = Group.new
user  = User.new
group.expects(:opened?).returns(true)
group.expects(:owner?).returns(true)
assert group.can_update?(user)

The problem is when I have "OR" conditions. With the first method ( can_create? ) I can't do that:

group = Group.new
user  = User.new
group.expects(:opened?).returns(true)
group.expects(:owner?).returns(true)
group.expects(:member?).returns(true)
assert group.can_create?(user)

Because ( owner? and member? methods can be true/false ).

Vega
  • 27,856
  • 27
  • 95
  • 103
  • 1
    I deal with this problem all the time. I find this somewhat of a pain to test. At one point I tested all the possibilities of a predicate chain like this one (https://gist.github.com/Aupajo/3909485), but now I'm not so sure this isn't the fault of poor design. Looking for a good answer, too. – Aupajo Aug 27 '13 at 23:40
  • Can you post the entire class the `can_create?` method is contained in? – rudolph9 Aug 27 '13 at 23:45
  • Thanks Aupajo and rudolph9. I updated my question adding more details. – Diego Nogueira Aug 28 '13 at 01:22

1 Answers1

0

My first guess is to write several tests:

test 'with opened and owner' do
  group = Group.new
  user  = User.new
  group.expects(:opened?).returns(true)
  group.expects(:owner?).returns(true)
  assert group.can_create?(user)
end

test 'with opened and member' do
  group = Group.new
  user  = User.new
  group.expects(:opened?).returns(true)
  group.expects(:owner?).returns(false)
  group.expects(:member?).returns(true)
  assert group.can_create?(user)
end

test 'with opened and not member or owner' do
  group = Group.new
  user  = User.new
  group.expects(:opened?).returns(true)
  group.expects(:owner?).returns(false)
  group.expects(:member?).returns(false)
  assert group.can_create?(false)
end

Then you can refactor you tests to have something cleaner, so you want to use stubs instead of expects to avoid the OR problem:

def assert_can_create(params, expected)
  group = Group.new
  user  = User.new
  group.stubs(:opened?).returns(params[:opened])
  group.stubs(:owner?).returns(params[:owner])
  group.stubs(:member?).returns(params[:member])

  assert group.can_create?(expected)
end

test 'can_create possibilities' do
  assert_can_create({opened: true, owner: true, member:true}, true)
  assert_can_create({opened: true, owner: true, member:false}, true)
  assert_can_create({opened: true, owner: false, member:true}, true)
  assert_can_create({opened: true, owner: false, member:false}, false)
  assert_can_create({opened: false, owner: true, member:true}, false)
  [...]
end

after all, it's not so long for this example. If you have lots and lots of conditions, you might want something like Aupajo. But I think you'll end to write your own, since you will have some specifics needs.

regards

joel1di1
  • 773
  • 5
  • 13