4

I'm working with the FakeItEasy library to create fakes for my unit tests.

I have a ClassUnderTest on which I want to test the method MethodToTest(Data dataObject). This method is calling a method of an interface which I want to fake:

public interface IFoo
{
  void Execute(Action<IDataAccess> action);
}

public class ClassUnderTest
{
  private IFoo _foo;

  public ClassUnderTest(IFoo foo)
  {
    _foo = foo;
  }

  public void MethodToTest(Data dataObject)
  {
    _foo.Execute(dataAccess => dataAccess.Update(dataObject));
  }
}

public interface IDataAccess
{
  void Update(Data data);
}

public class Data
{
  public int Property { get; set; }
}

In my unit tests I want to check if the test method calls the interface correctly (with the correct property value):

[TestClass]
public class UnitTest1
{
  [TestMethod]
  public void TestMethod1()
  {
    var foo = A.Fake<IFoo>(x => x.Strict());
    A.CallTo(() => foo.Execute(dataAccess => dataAccess.Update(A<Data>.That.Matches(d => d.Property == 20))));      

    var cut = new ClassUnderTest(foo);

    cut.MethodToTest(new Data { Property = 20 });      
  }
}

But something is configured wrong in this test. I get the exception:

Test method TestProject1.UnitTest1.TestMethod1 threw exception: FakeItEasy.ExpectationException: Call to non configured method "Execute" of strict fake.

Does somebody have an idea of how I have to configure the CallTo() statement correctly?

Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
rhe1980
  • 1,557
  • 1
  • 15
  • 36
  • Easily, I'd say ...? :) (ok, ok, I'll give this a read over ... ) – Noctis Nov 14 '13 at 09:37
  • Are you certain the code you've presented is even compiling? `ClassUnderTest` does not have a parameterless constructor (I'm assuming it's a class - but that is also missing from the code), but you seem to use one... – decPL Nov 14 '13 at 10:02
  • @decPL: you are right, I corrected the sample above. the foo-fake is passed in the costructor. – rhe1980 Nov 14 '13 at 10:14
  • and `dataAccess` is...? – decPL Nov 14 '13 at 10:17
  • @decPL: this is the issue I have. calling the Execute method on the fake I have to define that the foo fake offers a IDataAccess which the MethodToTest can use for calling the .Update(dataObject) method – rhe1980 Nov 14 '13 at 10:26
  • 1
    I think @decPL is on to something - that's how I'd check that `Execute` was called, but I also think that something else is going on, aside from all the compilation errors (which persist - there's no "class" by `ClassUnderTest`, if nothing else). FakeItEasy complains that `foo` is a "Strict fake", which is not the default. Is there additional code you're not showing? Or maybe an `IFakeConfigurator` somewhere? – Blair Conrad Nov 14 '13 at 12:24
  • @BlairConrad: thanks for your help. I revised my sample. Hope now is more understandable. You're right, normaly I also do not use Strict fakes but the .MustHaveHappened() to demand the assert. But i got the same error with this. – rhe1980 Nov 14 '13 at 13:56

2 Answers2

4

The updated example really helps, @rhe1980.

First some notes about the test you supplied:

  1. the A.CallTo method doesn't do anything - it's not setting up behaviour (with a .Invokes or a .Returns or even a .DoesNothing) or verifying that the method has been called (for example with .MustHaveHappened).
  2. Comparing Actions appears to be tough. I did find some advice over at Compare Delegates Action<T>, but if it were me, I'd take a slightly different tack.

Instead of attempting to compare the Action delegate to a reference model, I figured I could emulate this by capturing the action supplied to Execute and then running it on an IDataAccess and see what the action does. Fortunately, we have FakeItEasy to help with that!

I had success with this test:

[TestMethod]
public void TestMethod1()
{
    // Arrange
    var foo = A.Fake<IFoo>(x => x.Strict());

    var fakeDataAccess = A.Fake<IDataAccess>();

    A.CallTo(() => foo.Execute(A<Action<IDataAccess>>.Ignored))
                    .Invokes((Action<IDataAccess> action)=>action(fakeDataAccess));

    var cut = new ClassUnderTest(foo);

    // Act
    cut.MethodToTest(new Data { Property = 20 });

    // Assert
    A.CallTo(() => fakeDataAccess.Update(A<Data>.That.Matches(d => d.Property == 20)))
        .MustHaveHappened();
}

I hope it helps.

Community
  • 1
  • 1
Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
1

If I understood your intentions correctly, you need to use something as follows:

A.CallTo(() => foo.Execute(A<Action<IDataAccess>>.Ignored).MustHaveHappened();
decPL
  • 5,384
  • 1
  • 26
  • 36
  • I agree, and ideally after running `MethodToTest`. I think there are other problems with the sample code, though. See my comment on the question. – Blair Conrad Nov 14 '13 at 12:26