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
I recently started evaluating TypeMock for my company and am having the following problem.


I have a collection class:
public abstract class MyAbstractCollection: IList
{
  private ArrayList list = new ArrayList();

  public void FillData()
  {
      //fill collection
      //...
  }
  protected internal ArrayList List
  {
      get
      {
          return _list;
      }
  }
  IEnumerator IEnumerable.GetEnumerator()
  {
       return _list.GetEnumerator();
  }
  //other methods
  // ...
}


Then multiple collection classes that inherit off of that
This one holds multiple MyObject's
public class MyCollection: TtgBpoCollection
{
   public MyCollection()
   {
   }

   public MyObject AddNew()
   {
      MyObject obj = new MyObject();
      List.Aadd(obj);

      return obj;
   }
}

public class MyObject
{
   private int i = 0;

   public MyObject()
   {
   }

   public int Value
   {
      get
      {
         return i;
      }
      set
      {
         i = value;
      }
   }
}


Then in my code i'm looping through the collection in my MainClass
private int Sum()
{
   MyCollection collection = new MyCollection();
   int sum = 0;

   collection.FillData();

   foreach(MyObject obj in collection)
   {
       sum = sum + obj.Value;
   }

  return sum;
}


Now in my nMock test I want to test this function by mocking collection
[Test]
public void N01_TestSum()
{
  MainClass main = new MainClass();
  MyCollection collection = new MyCollection();

  //fill collection with test data
  //...

  Mock collectionMock = MockManager.Mock(typeof(MyCollection));
  collectionMock .ExpectAndReturn("GetEnumerable", CreateEnumerator(collectionMock), null);

  int returnedValue = main.Sum();
  Assert.AreEqual(5, returnedValue, "Incorrect sum");
}

public IEnumerator CreateEnumerator(MyCollection collection)
{
   ArrayList list = new ArrayList();

  foreach(MyObject obj in collection)
  {
     list.Add(obj);
  }

  return list.GetEnumerator();
}


I always get the error:
MyTest.N01_TestSum : TypeMock.TypeMockException :
*** No method GetEnumerable in type MyCollection returns System.Collections.ArrayList+ArrayListEnumeratorSimple

I've simplified everything out but this gets the main idea across. I apologize for any syntax mistakes that may be in there. I'm running the latest version of TypeMock with nUnit and VS 2003.

Am I missing something or is there another way to mock a collection that is being used in a foreach loop?

Thanks!
asked by RSylvester (880 points)

17 Answers

0 votes
Ohad,
I'm confused by your answer. Your saying that my MyAbstractCollection class is implementing IEnumerable's GetEnumerator method by doing:
IEnumerator IEnumerable.GetEnumerator() 
{ 
     return _list.GetEnumerator(); 
}


Instead of IList's which would be:
public IEnumerator GetEnumerator() 
{ 
     return _list.GetEnumerator(); 
}


Is that what you're saying?

I'm not sure why we implemented that the way we did. Is there a problem with how TypeMock is trying to process this? Or did we just implement this wrong?

Thank you for your help
answered by RSylvester (880 points)
0 votes
You might want to use the TypeMock Tracer.
This will show you all your expectations and when they where called.
It is a great tool to use when trying to 'debug' the mocks.
The Tool has 3 views.
1. is the type/instance view in which you can see the instances that are mocked and the methods that are mocked/not mocked.
2. the call stack where the expectation and calls are shown.
(If you choose a line in one view the corresponding lines are shown in the other view)
3. Property view that changes with the line you choose.
answered by scott (32k points)
0 votes
Hi
I'm confused by your answer. Your saying that my MyAbstractCollection class is implementing IEnumerable's GetEnumerator method by doing:
Code:
IEnumerator IEnumerable.GetEnumerator()
{
return _list.GetEnumerator();
}


Instead of IList's which would be:
Code:
public IEnumerator GetEnumerator()
{
return _list.GetEnumerator();
}
Is that what you're saying?

As Scott said the tracer can show you the way...
Is there a problem with how TypeMock is trying to process this? Or did we just implement this wrong?

What I said before is that
IEnumerator IEnumerable.GetEnumerator()

should not be used unless your class implementing another interface that has the same method signature.
This syntax comes to solve the ambiguity problem that will raise its ugly head in this case.
Here is an example:

    interface IMyInterface1
    {
        void Method();
    }

    interface IMyInterface2
    {
        void Method();
    }

    public class MyClass : IMyInterface1, IMyInterface2
    {
        public void Method()
        {
            Console.WriteLine("IMyInterface1.Method");
        }

        void IMyInterface2.Method()
        {
            Console.WriteLine("IMyInterface2.Method");
        }
    }

    class Program
    {        
        static void Main(string[] args)
        {
            MyClass c = new MyClass();
            c.Method();
            //You can access IMyInterface2 Method only by casting to the IMyInterface2
            IMyInterface2 i = c;
            i.Method();
        }
    }
answered by ohad (35.5k points)
0 votes
Okay I think I understand what your saying now. I've run it through the tracer and run some more tests.

We don't implement another GetEnumerator() in this class. I was talking with my manager and we think that the reason that IEnumerator IEnumerable.GetEnumerator() is used is that we didn't want to expose the GetEnumerator() function.

It doesn't sound like it but just to make sure, can TypeMock mock this the way it is currently implemented? (Explicity defining which interface it is for)

I appreciate your help with this.
answered by RSylvester (880 points)
0 votes
Hi
Why are trying to mock GetEnumerator?
It seems that what you want is to mock the List property.
You can do that by using Mock.ExpectGet method.
Since I can't see all the code I could be wrong ...
answered by ohad (35.5k points)
0 votes
Hi,
The reason I am using the GetEnumerator Method and not just mocking the List property is that in the code I want to test I am using a foreach loop, looping over a collection of type MyCollection so I need to mock the GetEnumerator function.
answered by RSylvester (880 points)
0 votes
Perhaps I can help here. 8)

We want to test Sum() by mocking the real implementation of MyCollection and testing it under different scenarios.
Lets remember that we don't really want to mock and implement enumerators and other mscorlib methods, what we really want is to fill the collection with different values and to test Sum().

There are a few ways to do this, I think that the most elegent way is to mock FillData and to actually fill the collection with fake test data using Dynamic Return Values. This pattern will allow us to change the future instace of MyCollection after it has been created.

Here is an example:
[Test]
public void N01_TestSum()
{
  MainClass main = new MainClass();
  // mock next future instance
  Mock collectionMock = MockManager.Mock(typeof(MyCollection));
  // will fill collection with test data when FillData is called
  collectionMock.ExpectAndReturn("FillData", new DynamicReturnValue(FillTestData));

  int returnedValue = main.Sum();
  Assert.AreEqual(5, returnedValue, "Incorrect sum");
} 

private object FillTestData( object[] parameters, object context)
{
   MyCollection collection = (MyCollection)context;
   // Fill data ...
   collection.Add(1);


   return null; // FillData() is void so this doesn't matter
}


:arrow: Notes:
1. You can use ExpectAndReturn for void methods when the return value is DynamicReturnValue
2. The delegate is executed when the mocked method is called
3. The delegate receives the actuall mocked object.
4. The return value is ignored for void methods.

I hope this helps
answered by scott (32k points)
...