How-To: Setting Behavior for Future Objects with Isolator++

One of the biggest hurdles in writing tests for legacy code are future dependencies. They are called “future” objects, because they are created inside the class under test, rather then injected into it by the test.

Let’s look at our Person constructor:

Person::Person()

{

      address = new Address();

}

That address, right there, is a future object. Why is that a problem? Let’s look at Person’s other constructor:

Person::Person(Address* initialAddress)

{

      address = initialAddress;

}

As you can see, in the first constructor, the Address dependency is created inside the constructor. In the second constructor, it’s injected. If it’s injected, the test can create a FAKE object and inject it. But in the first case, we don’t have control on the creation of the object.

Or do we?

One of powerful features of Isolator++ is to fake future objects. Here’s an example of how to test the IsLivingInNY method:

bool Person::IsLivingInNY()

{

      if (strcmp (address->GetCity(),"NYC")==0)

{

            return true;

      }

      else

            return false;

}

How can I change the behavior of GetCity if address is created in the constructor? Easily. Here’s how the test looks like:

    1 TEST_F(PersonTests, IsLivingInNY_UsingDefaultConstructor_ReturnsTrue)

    2 {

    3     Address* fakeAddress = FAKE_ALL(Address);

    4     WHEN_CALLED(fakeAddress->GetCity()).Return("NYC");

    5 

    6     // The internal address is now created as fake

    7     Person person;

    8 

    9 

   10     ASSERT_TRUE(person.IsLivingInNY());

   11     ISOLATOR_CLEANUP();

   12 }

  • In line 3, we’re using the FAKE_ALL macro to create a proxy to all future created objects of type Address. Every Address object that will be created past this point, will be faked, and behave as we tell it to!
  • That’s why we’re using WHEN_CALLED in line 4. We’re telling the future object to return “NYC” when GetCity is called.
  • In line 7, on creating the Person object, instead of a real Address object created, the returned object is now the fake one we created. Yes, without changing the code of the default constructor!
  • And in line 11, we clean all fake settings. That means the next Address to be created will be real.

With FAKE_ALL you can set behaviors of future dependency easily, and without changing the existing code.

Gil Zilberfeld