Conditional Behavior Faking

Top  Previous  Next

Isolator++ Professional allows you to return different values of a faked method, based on parameter values.

To achieve this use the Conditional Checkers in the CallTo statement.

 

API

Meaning

Example

A::Any

Matches any argument

a.CallTo(fake->Foo(A::Any()).WillReturn(1);

A::Type<type>

Argument must be of the specified type

a.CallTo(fake->Foo(A::Type<char>()).WillReturn(1);

A::Eq and  A::EqRef

Argument must equal a value

a.CallTo(fake->Foo(A::Eq(100))).WillReturn(1);

A::Ne and A::NeRef

Argument must not equal a value

a.CallTo(fake->Foo(A::Ne(3))).WillReturn(1);

A::Lt and A::LtRef

Argument is smaller than the value

a.CallTo(fake->Foo(A::Lt(5))).WillReturn(1);

A::Le and A::LeRef

Argument is smaller or equals

a.CallTo(fake->Foo(A::Le(4))).WillReturn(1);

A::Gt and A::GtRef

Argument is greater than the value

a.CallTo(fake->Foo(A::Gt(10.2))).WillReturn(1);

A::Ge and A::GeRef

Argument is greater or equals

a.CallTo(fake->Foo(A::Ge(1))).WillReturn(1);

A::Matches and A::MatchesRef

Matches a custom lambda condition

a.CallTo(fake->Foo(A::Matches([](char* s) 

  { return  !strcmp(s, "typemock"); }))

  .WillReturn(1);

A::SetOut(...).WhenIn

Assigns an out value, if condition is met

a.CallTo(fake->Foo(A::SetOut(value).WhenIn(A::Eq(100))))

  .WillReturn(1);

A::SetOut(...).WhenInMatches

Assigns an out value, based on lambda

a.CallTo(fake->Foo(A::SetOut(value).WhenInMatches([](char* s)

 { return  !strcmp(s, "typemock"); }))

  .WillReturn(1);

 

Note: Use the Ref APIS for by reference-type parameters.

 
Note: Object comparisons (std::string for example) must be done using A::Matches.
A::Eq/A::Ne can be used on natives, char* and pointers.

 

Note: Isolator++ Professional prioritizes conditional fakes and sequences them. If no match is found, unconditional behaviors are used.

 

Examples

 

Example 1: Conditional for Instance Method

 

Assuming the following class is in the production code:

 

class Person

{

public:

   bool IsPartOfGroup(int newGroupID) ; 

};

 

To create a test that returns true only for group 2:

 

TEST_F(Examples, ConditionalForInstanceMethod)

{

   // Arrange

   auto a = Isolator();  

   Person* livePerson = new Person();

  

   a.CallTo(livePerson->IsPartOfGroup(A::Eq(2))).WillReturn(true);

 

   // Act

   auto result = livePerson->IsPartOfGroup(2);  

 

   // Assert

   ASSERT_TRUE(result); 

}

 

Note: Isolator++ native operators (A::Eq etc.) also accept objects if the underlying operators exist for the objects.

Assume we have a class Logger, with an instance method WriteStringLine(const std::string&) that prints an std::string.

You can verify that the method was called with a specific string like this:

 

TEST_F(Examples, ConditionalForInstanceMethod)

{

   // Arrange

   auto a = Isolator();  

   auto logger = a.Fake.Instance<Logger>();

 

   logger->WriteStringLine("hello");

   logger->WriteStringLine("goodbye");

 

   // Act

   auto result1 = a.CallTo(logger->WriteStringLine(A::Eq("hello")).GetTimesCalled();

   auto result2 = a.CallTo(logger->WriteStringLine(A::Ne("hello")).GetTimesCalled();

   

   //It is possible as well with A::Matches API)

   auto result3 = a.CallTo(logger->WriteStringLine(A::Matches([](const std::string& str) { return str == "hello"; })).GetTimesCalled();

 

 

   // Assert

   ASSERT_EQ(result1, 1); 

   ASSERT_EQ(result2, 1);

   ASSERT_EQ(result3, 1); 

}

 

Here is an example for the other native operators (the comparison is alphabetical for std::string):

 

TEST_F(Examples, ConditionalForInstanceMethod)

{

   auto a = Isolator();  

   auto logger = a.Fake.Instance<Logger>();

 

   logger->WriteStringLine("apple");

   logger->WriteStringLine("banana");

   logger->WriteStringLine("cat");

   logger->WriteStringLine("dog");

 

   auto res = a.CallTo(logger->WriteStringLine(A::Lt("dog"))).GetTimesCalled();

   ASSERT_EQ(res, 3);

 

   res = a.CallTo(logger->WriteStringLine(A::Le("dog"))).GetTimesCalled();

   ASSERT_EQ(res, 4);

 

   res = a.CallTo(logger->WriteStringLine(A::Gt("apple"))).GetTimesCalled();

   ASSERT_EQ(res, 3);

 

   res = a.CallTo(logger->WriteStringLine(A::Ge("apple"))).GetTimesCalled();

   ASSERT_EQ(res, 4);

}

 

Example 2: Conditional for Reference-Type Argument

 

Assume the following class:

 

class Person

{

public:

   bool IsPartOfGroupRef(int& newGroupID) ; 

};

 

To create a test that returns true only for group 2:

 

TEST_F(Examples, ConditionalForInstanceMethod)

{

   // Arrange

   auto a = Isolator();  

   Person* livePerson = new Person();

  

   a.CallTo(livePerson->IsPartOfGroupRef(A::EqRef(2))).WillReturn(true);

 

   // Act

   int id = 2;

   auto result = livePerson->IsPartOfGroup(id);  

 

   // Assert

   ASSERT_TRUE(result); 

}

 

 

Example 3: Conditional for Private Method

 

If the method IsPartOfGroup is private, use CallToPrivate:

 

 

a.CallToPrivate(A::Member(livePerson, IsPartOfGroup),A::Eq(2))).WillReturn(true);

 

 

Example 4: Conditional for Private Method

 

To create a custom condition, use A::Matches with a lambda. For example, return true for groups 2 and 5:

 

TEST_F(Examples, ConditionalForInstanceMethod)

{

   // Arrange

   auto a = Isolator();  

   Person* livePerson = new Person();

  

   a.CallTo(livePerson->IsPartOfGroup(A::Matches([](int i) 

     {return  i==2 || i==5 ;}))

     .WillReturn(true);

 

   // Act

   auto result = livePerson->IsPartOfGroup(2);  

 

   // Assert

   ASSERT_TRUE(result); 

}

 

 

Note: The A::Matches API can be used for specifying an overload of the method with the matching arguments.

 

 

Example 5: Out/By-Ref Parameter

 

If you need to conditionally fake a method with an out parameter:

 

class Person

{

public:

 

   char* name;

 

   bool GetNameWithRef(char** refName)

   {

 *refName = name;

      return false; 

   }

};

 

Test to return true and set the out parameter to "bar" when the referenced name is "typemock":

 

TEST_F(Examples, RefBehaviorChanging)

{

   // Arrange

   auto a = Isolator();  

   Person* livePerson = new Person();

   livePerson->name = "foo";        

 

   // will set argument to bar if it was "typemock"

   a.CallTo(livePerson->GetNameWithRef(A::SetOut("bar").WhenIn(A::EqRef("typemock")).WillReturn(true);

 

   char* arg = "typemock";

   // Act

   auto result = livePerson->IsPartOfGroup(arg);  

 

   // Assert

   ASSERT_TRUE(result); 

   ASSERT_STREQ(arg,"bar");

}

 

Note: We use A::EqRef as the argument is a pointer

 

Creating Custom Conditions between many arguments

 

To create a condition that requires testing multiple arguments between each other, use the DoInstead API, and put the logic within the lambda.
Note: Isolator++ Professional manages DoInstead as an unconditional statement and thus will be used after all conditions.

 

Example

 

Assuming the following class is in the production code:

 

class Person

{

public:

   bool IsPartOfGroup(int newGroupID, char *name)const {

   return false} 

};

 

Let's create a test that returns true only for group 2 with name "typemock"

 

TEST_F(Examples, DoInsteadForInstanceMethod)

{

   // Arrange

   auto a = Isolator();     Person* livePerson = new Person();        

 

   a.CallTo(livePerson->IsPartOfGroup(A::Any(),A::Any())).WillDoInstead([](int newGroupID, const char *name

 {

    return newGroupID == 2 && !strcmp(name"typemock");

 });

 

   // Act

   auto result = livePerson->IsPartOfGroup(2"typemock");  

 

   // Assert

   ASSERT_TRUE(result); 

}

 

 

 


Copyright  Typemock Ltd. 2009-2025.  All Rights Reserved.