Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use FakeItEasy's A.CallTo() on another method in same object

Using FakeItEasy, how do I check to see if my object's method calls another method on this same object?

The Test:

[TestMethod]
public void EatBanana_CallsWillEat()
{
  var banana = new Banana();
  var myMonkey = new Monkey();

  myMonkey.EatBanana(banana);

  //this throws an ArgumentException, because myMonkey is a real instance, not a fake
  A.CallTo(() => myMonkey.WillEat(banana)
    .MustHaveHappened();
}

The Class:

public class MyMonkey {
  private readonly IMonkeyRepo _monkeyRepo;

  public MyMonkey(IMonkeyRepo monkeyRepo) {
    _monkeyRepo = monkeyRepo;
  }

  public void EatBanana(Banana banana) {
    //make sure the monkey will eat the banana
    if (!this.WillEat(banana)) {
      return;
    }

    //do things here
  }

  public bool WillEat(Banana banana) {
    return !banana.IsRotten;
  }
}

I'm open to suggestions. If I'm going about this all wrong, please let me know.

like image 923
Josh Noe Avatar asked Jul 29 '13 16:07

Josh Noe


2 Answers

Why are you mocking tested object? What exactly are you trying to test? The verification that call to WillEat happened is of little value. What information does it server to consumer? After all, consumer doesn't care how method is implemented. Consumer cares what are the results.

What happens when monkey eats banana that is not rotten? Your test should answer this question:

[TestMethod]
public void EatBanana_CAUSES_WHAT_WhenBananaIsNotRotten()
{
    var repo = A.Fake<IMonkeyRepo>();
    var monkey = new Monkey(repo);
    var freshBanana = new Banana { IsRotten = false };

    monkey.EatBanana(freshBanana);

    // verifications here depend on what you expect from
    // monkey eating fresh banana
}

Note that you can make all sort of verifications to IMonkeyRepo, which is properly faked and injected here.

like image 107
k.m Avatar answered Sep 26 '22 08:09

k.m


It's possible to do this. If the WillEat method were virtual - otherwise FakeItEasy won't be able to fake it out.

With that change, you could do this:

[TestMethod]
public void EatBanana_CallsWillEat()
{
    var fakeMonkey = A.Fake<MyMonkey>();

    fakeMonkey.EatBanana(new Banana());

    A.CallTo(()=>fakeMonkey.WillEat(A<Banana>._)).MustHaveHappened();
}

I'm still not convinced it's a good idea (as I ranted in the comments) - I think you'd be better off relying on other observable behaviour, but I'm not familiar with your system. If you think this is the best way to go, the example code should work for you.

like image 28
Blair Conrad Avatar answered Sep 26 '22 08:09

Blair Conrad