chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
Hello. I am just getting started wtih TypeMock and have a question about how to best use the Natural TypeMocks style with Collections. I am using .NET 2.0 in VS2005 Team System. Here is some simple code I want to write a test for:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;


namespace MockCollectionTestConsole
{
   class Program
   {
      static void Main(string[] args)
      {
         User u = new User();

         if (IsAddressValid(u, "hardcoded2"))
            Console.WriteLine("match");

      }

      static bool IsAddressValid(User user, string validStreet)
      {
         bool result = false;

         foreach (Address a in user.Addresses)
         {
            if (a.Street == validStreet)
            {
               result = true;
               break;
            }
         }

         return result;
      }
   }

   public class User
   {
      private AddressCollection _addresses = new AddressCollection();

      public AddressCollection Addresses { get { return this._addresses; } }
   }

   public class Address
   {
      private string _street = string.Empty;

      public string Street
      {
         get { return _street; }
         set { _street = value; }
      }

      public Address(string street)
      {
         this._street = street;
      }
   }

   public class AddressCollection : IEnumerable<Address>
   {
      private List<Address> _list = new List<Address>();

      public AddressCollection()
      {
         this._list.Add(new Address("hardcoded1"));
         this._list.Add(new Address("hardcoded2"));
         this._list.Add(new Address("hardcoded3"));
      }

      #region IEnumerable Members

      public IEnumerator<Address> GetEnumerator()
      {
         return this._list.GetEnumerator();
      }

      System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
      {
         return ((IEnumerable)this._list).GetEnumerator();
      }

      #endregion
   }
   
}


So my question is, what is the best way to use Natural TypeMocks to be able to mock the collection.

[DeploymentItem("MockCollectionTestConsole.exe")]
[TestMethod()]
public void IsMatchStreetTest()
{
   using (RecordExpectations recorder = RecorderManager.StartRecording())
   {
// WHAT TO PUT HERE SUCH THAT I CAN SET THE COLLECTION OF user.Addresses in the IsAddressValid method to whatever I want????
//
// FOR EXAMPLE, LET"S SAY I WANT user.Addresses TO CONTAIN 2 Address OBJECTS, THAT
// RETURN "test1" AND "test2" FOR THE Street PROPERTY
//
// WHAT IS THE BEST WAY TO DO THAT?
   }

      User user = new User();

      string toMatch = "test2";

      bool expected = true;
      bool actual;

      actual = MockTestProject.MockCollectionTestConsole_ProgramAccessor.IsAddressValid(user, toMatch);

      Assert.AreEqual(expected, actual, "MockCollectionTestConsole.Program.IsMatchStreet did not return the expected value");
   }
}
asked by chujanen-promega (680 points)

4 Answers

0 votes
Hi,
Welcome to TypeMock.
It is quite hard to understand what you are testing, so it is hard to know how to mock it.
In your example I would not use mocks at all, but create a collection and run the test.
[TestMethod()]
public void IsMatchStreetTest()
{
      string toMatch = "test2";

      User user = new User();
      user.Addresses.Clear();
      user.Addresses.Add(new Address("test1"));
      user.Addresses.Add(new Address(toMatch));

      bool expected = true;
      bool actual;

      actual = MockTestProject.MockCollectionTestConsole_ProgramAccessor.IsAddressValid(user, toMatch);

      Assert.AreEqual(expected, actual, "MockCollectionTestConsole.Program.IsMatchStreet did not return the expected value");
   }
}

If you cannot access the Collection Field you can use TypeMocks StateObject to change the field in the object.
User user = new User();
ObjectState objState = new ObjectState(user);
AddressCollection addresses =  objState.GetField("_addresses ");
addresses.Clear();
addresses.Add(new Address("test1"));
addresses.Add(new Address(toMatch));


It is also possible to mock the Addresses Property. Here is a NaturalMocks way to do it:
User user = new User();
AddressCollection fakeAddresses = new AddressCollection();
fakeAddresses .Clear();
fakeAddresses.Add(new Address("test1"));
fakeAddresses.Add(new Address(toMatch))

// switch Addresses with fake address
using (RecordExpectations recorder = RecorderManager.StartRecording())
{
   recorder.ExpectAndReturn(
     user.Addresses
     fakeAddresses);
}
answered by scott (32k points)
0 votes
Thanks Scott for the quick response. I can see where my example doesn't make a whole lot of sense, but I was trying to simplify and generalize things.

In your solution, you use a real AddressCollection object, but let's say for the sake of argument that in these tests, we don't want AddressCollection to really be constructed as in its real implementation it does some unwanted things for the purposes of our test (writes stuff to a database maybe).

Another problem with your solutions (not that I know they are meant to be bullet proof, I am just trying to rationalize why you may not be able to implement them the way you proposed) is that the AddressCollection does not actually have the Clear and Add methods.

What I was hoping is that there was some way to magically be able to return mocked objects for a mocked collection, but I am guessing that is not easily achievable, if at all.

Finally, it seems to me that the more a test relies on knowledge of the implementation of other classes, the more likely it is to break if the code in the other classes changes. That is why if possible I would like to mock as much of the behavior as possible to write better unit tests, meaning only test the code in the unit that is meant to be tested.

Please comment and offer any advice. Thanks!
answered by chujanen-promega (680 points)
0 votes
Here is another way you might use:
List<Address> fakeList = new List<Address>();
fakeList.Add(new Address("test1"));
fakeList.Add(new Address(toMatch));
IEnumerator<Address> fakeEnumerator = fakeList.GetEnumerator(); 

// mock next Addresses to return fake values.
using (RecordExpectations recorder = RecorderManager.StartRecording())
{
   AddressCollection mockedCollection = new AddressCollection();
   recorder.ExpectAndReturn(
     mockedCollection.GetEnumerator()
     fakeEnumerator);
}


You could mock the IEnumerator (Current and MoveNext) but I would simply switch the Collection to another collection.
answered by scott (32k points)
0 votes
Thanks Scott, that's the kind of thing I was trying to understand.
answered by chujanen-promega (680 points)
...