3

Am trying to use FakeItEasy. I have a particular scenario for which either am unable to understand how to test or is not possible using FakeItEasy

Lets say I have a base class and derived class which look like this

public class BaseClass {
     protected bool BaseClassMethod() { return true; }
   }

public class DerivedClass : BaseClass {
     public void DoSomething(){
        if(BaseClassMethod()) Console.WriteLine("Bla");
        else Console.WriteLine("Worked");
  }
}

Now I want to be able to test the DerivedClass, but be able to fake BaseClassMethod(). I tried doing something like

var fakeBaseClass = A.Fake<BaseClass>();
A.CallTo(fakedBaseClass).Where(x => x.Method.Name   "BaseClassMethod")).WithReturnType<bool>(). Returns(false); 
var derivedClass = new DerivedClass(); // Am hoping that the DerivedClass will use the Faked Baseclass that I have created above.
derivedClass.DoSomething()

This doesnt do what I expect it to do. Am i missing something here or is this not possible with FakeItEasy?

Thanks Karthik

Karthik Balasubramanian
  • 1,127
  • 4
  • 13
  • 36

1 Answers1

3

There are a few problems with your approach.

The first problem is that you've no connection between the fakeBaseClass you created and derivedClass, so there's no way for them to influence one another. To accomplish what I think you are trying to do, you really want to make a fake DerivedClass and manipulate its behaviour (actually, in general, this type of testing is contentious, but let's focus on the mechanics and set aside whether it's a good idea for now).

By faking DerivedClass, FakeItEasy will actually be instantiating a new type of class that derives from DerivedClass and therefore will call and have access to all (protected or public) methods of DerivedClass and BaseClass. Then you can set up the behaviour you want from BaseClassMethod and exercise DoSomething and hopefully get the results you want.

The second thing that will cause problems when we try this is that BaseClassMethod is not virtual. FakeItEasy (and isolation frameworks of its ilk) cannot fake out any method that is not virtual. You can learn more about what's fakeable at What can be faked.

So, putting together those two changes, I get code like this:

public class BaseClass
{
    protected virtual bool BaseClassMethod()
    {
        return true;
    }
}

public class DerivedClass : BaseClass
{
    public string DoSomething()
    {
        if (BaseClassMethod())
        {
            return ("Bla");
        }
        else
        {
            return ("Worked");
        }
    }
}

[Test]
public void MethodName_StateUnderTest_ExpectedBehavior()
{
    var fakedDerivedClass = A.Fake<DerivedClass>();
    A.CallTo(fakedDerivedClass)
        .Where(x => x.Method.Name == "BaseClassMethod")
        .WithReturnType<bool>()
        .Returns(false);

    Assert.That(fakedDerivedClass.DoSomething(), Is.EqualTo("Worked"));
}

This test passes. Note that I've made changes to your original (aside from correcting typos):

  1. BaseClassMethod is now virtual
  2. I'm creating a fake DerivedClass for testing, and
  3. DoSomething returns a string, rather than writing to the Console. That wasn't strictly necessary, but made my test easier to write.

Note that if BaseClassMethod is not virtual, then there's no chance it will return anything other than true, and I don't see much point in writing a test to see what will happen when DoSomething gets a false from it.

For more discussion on why faking the class under test (instead of that class's collaborators) may be a bad idea, see comments on Use FakeItEasy's A.CallTo() on another method in same object and my answer to Using FakeItEasy, is it possible to create a dummy object of a type that takes generic type parameters.

But how you feel about the approach is something that you will have to come to terms with on your own.

ikerbera
  • 195
  • 1
  • 3
  • 15
Blair Conrad
  • 233,004
  • 25
  • 132
  • 111