Controlling Base Class Behavior


Ignoring Base Class Constructor

When creating fake objects you sometimes need to call the object's real constructor, but not call its base class constructor. This is useful when the fake object's constructor performs initializations required for the test, but the base classes have external dependencies in their construction which should be faked. This is done by defining constructor and base constructor behavior in Isolate.Fake.Instance().

Example: the TopCustomerData object inherits a base class which has a dependency in a database connection (see code at the bottom).  We want to create a fake object out of Customers, but avoid calling the base class constructor as it would try to connect to the external database. This is done by specifying the class' constructor will be called, while its base constructor will be ignored:

[TestMethod, Isolated]
public void FakeBaseClassConstructor_FakeBaseClassWhichThrowsOnCtor()
{
    // fake data manipulations on DataAccess
    var fakeDataAccess = Isolate.Fake.Instance<DataAccess>();
    Isolate.WhenCalled(() => fakeDataAccess.GetTopCustomer(null)).WillReturn(new Customer() {Name = "test"});
    Isolate.Swap.NextInstance<DataAccess>().With(fakeDataAccess);

    // create an instance of TopCustomerData that will behave like a normal instance, but avoid calling the base class constructor
    var customerData = Isolate.Fake.Instance<TopCustomerData>(Members.CallOriginal, ConstructorWillBe.Called,
                                                         BaseConstructorWillBe.Ignored);
   
    // verify the top customer is the same one that data access returned
    Assert.AreEqual("test", customerData.GetCustomer().Name);
}

A TypeMockException will be thrown if you are trying to fake base constructor behavior on types which are not inherited (i.e inherit from System.Object) or classes that inherit from mscorlib types

You cannot fake base class behavior on interfaces as they don't inherit from concrete base classes

Instead of always faking the immediate base class constructor, we can define at which level in the hierarchy the constructor will be faked. All constructors from the class being faked up to the defined base type will be called, and the constructor of the defined type (and all types it inherits from) will be faked. This is done by providing Isolate.Fake.Instance() with the base type to fake. A TypeMockException will be thrown if the base class to ignore is not in the inheritance chain of the faked type.

These are the test classes used in this example:

abstract class RepositoryBase
{
    protected static DataTable table;
    public RepositoryBase()
    {
        PopulateData(table);
    }

    protected void PopulateData(DataTable dataTable)
    {
        // implementation will rely on an external data connection
        throw new NotImplementedException();
    }
}

class TopCustomerData : RepositoryBase
{
    private Customer customer;
    protected static DataAccess dataAccess;
    public TopCustomerData()
    {
        dataAccess = new DataAccess(table);
        customer = dataAccess.GetTopCustomer(table);
    }

    public Customer GetCustomer()
    {
        return customer;
    }
}

public class DataAccess
{
    public DataAccess(DataTable table)
    {
    }
    public Customer GetTopCustomer(DataTable table)
    {
        throw new NotImplementedException();
    }
}


Copyright © Typemock Ltd. 2004-2010. All Rights Reserved.