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
Hi,

I'm getting the following exception using TypeMock 3.7.1 and .Net 2.0 when I try to use natural mocks with my code which uses generics:
Test method TestProject1.MyClassTest.method1Test threw exception: System.Reflection.AmbiguousMatchException: Ambiguous match found..

Here's a small testcase to reproduce it. The code being tested is:
public interface intC<T>
{
    void blah(T myInt);
}
public class classB<T>
{
    public intC<T> Selected(IEnumerable foo)
    {
        return null;
    }
    public intC<T> Selected(intC<T> bar)
    {
        return null;
    }
}
public class classA<T>
{
    public classB<T> B
    {
        get
        {
            return null;
        }
    }
}
public class MyClass
{
    public static void method1()
    {
        classA<int> a = new classA<int>();
        a.B.Selected((IEnumerable) null).blah(4);
    }
}


And here is the unit test code:
[TestMethod()]
public void method1Test()
{
    classA<int> a = new classA<int>();
    using (RecordExpectations recorder = RecorderManager.StartRecording())
    {
        a.B.Selected((IEnumerable) null).blah(4);
    }
    MyClass.method1();
}


Also, if you change classA to be static you then get a NullReferenceException from TypeMock when creating the natural mock. That might actually be a different bug.
asked by tibor (1.8k points)

12 Answers

0 votes
Hi Tibor
Thanks for reporting the bug.
We will send the patch offline.
answered by ohad (35.4k points)
0 votes
Hi Tibor
I sent you the patch.
Please note that if you'll run the test as it is now you will get a NullReferenceException.
In order to run it you need to mock classA.

[TestMethod()] 
public void method1Test()
{            
  using (RecordExpectations recorder = RecorderManager.StartRecording())
  {
     classA<int> a = new classA<int>();
     a.B.Selected((IEnumerable)null).blah(4);
  }
  MyClass.method1();
}
answered by ohad (35.4k points)
0 votes
Hi Ohad,

I tested the patch and it indeed fixes the problem in my real unit test.
Thanks for the quick turnaround! Very much appreciated.

Tibor
answered by tibor (1.8k points)
0 votes
Hi Ohad,

I've been using the patch you provided and when I modify my code to use CheckArguments I get the following exception:
Test method TestProject1.MyClassTest.method1Test threw exception: System.NullReferenceException: Object reference not set to an instance of an object..

Note that this is not the same NullReferenceException as in my original test case (which was my fault). This is occuring in the RecordExpectations using block and the stack trace is pointing towards a TypeMock problem.

Here's the new testcase that shows this problem. It's a slight variation on the original. The test code is as follows:
public interface intC<T>
{
    void blah(T myInt);
}
public class classC<T> : intC<T>
{
    public void blah(T myInt)
    {
        throw new NotImplementedException();
    }
}
public class classB<T>
{
    public intC<T> Selected(IEnumerable foo)
    {
        return null;
    }
    public intC<T> Selected(intC<T> bar)
    {
        return bar;
    }
}
public class classA<T>
{
    public classB<T> B
    {
        get
        {
            return null;
        }
    }
}
public class MyClass
{
    public static classC<int> foo = new classC<int>();
    public static void method1()
    {
        classA<int> a = new classA<int>();
        a.B.Selected(foo).blah(4);
    }
}


And this is the new test method:
[TestMethod()]
public void method1Test()
{
    intC<int> foo = MyClass.foo;
    using (RecordExpectations recorder = RecorderManager.StartRecording())
    {
        recorder.DefaultBehavior.CheckArguments();
        classA<int> a = new classA<int>();
        a.B.Selected(foo).blah(4);
    }
    MyClass.method1();
}
answered by tibor (1.8k points)
0 votes
Hi Tibor
Sorry it is a bug. :twisted:
I will send the fix offline.
answered by ohad (35.4k points)
0 votes
Hi Tibor
I sent the patch to your Yahoo mail.
Check it out.
answered by ohad (35.4k points)
0 votes
Hi Ohad,

Still no go :(
When I try it with the test case that passes of course, but in my real program I'm now getting a different exception. Even before I tried to add back the DefaultBehavior.CheckArguements() I decided to run the test again and found that it's now failing. It was passing before.

Here's the exception:
Test method xxxx.ReadTest threw exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: GenericArguments[0], 'xxxx.ClassA', on 'xxxx.ClassB`1[T]' violates the constraint of type 'T'. ---> System.TypeLoadException: GenericArguments[0], 'xxxx.ClassA', on 'xxxx.ClassB`1[T]' violates the constraint of type parameter 'T'..

and this is the stack trace:
at System.RuntimeTypeHandle._Instantiate(RuntimeTypeHandle[] inst)
at System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle[] inst)
at System.RuntimeType.MakeGenericType(Type[] instantiation)
--- End of inner exception stack trace ---
at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, Type[] genericArguments, Exception e)
at System.RuntimeType.MakeGenericType(Type[] instantiation)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at p.a(Type A_0, Type[] A_1)
at TypeMock.RecorderManager.a(Object A_0, Object A_1, MethodInfo A_2)
at TypeMock.RecorderManager.a(String A_0, MethodBase A_1, MethodInfo A_2, Boolean A_3, Object A_4, Object A_5)
at TypeMock.RecorderManager.a(String A_0, String A_1, Object A_2, Object[] A_3, MethodBase A_4, Object A_5, StackTrace A_6)
at TypeMock.MockManager.a(String A_0, String A_1, Object A_2, Object A_3, Object[] A_4)
at TypeMock.InternalMockManager.getReturn(Object that, String typeName, String methodName, Object methodParameters, Object p1)
at xxxx.ClassC`2.Selection(IEnumerable elements)
at xxxx.ReadTest()

In the above, ClassC.Selection() returns the ClassB<T> that the exception is complaining about. However, the T in ClassB<T> is not the ClassA that the exception mentions. Also, T has a constraint that it inherits from a base class and a constraint that it be new-able like this:
where T : BaseClass, new()

Unfortunately I don't have time now to narrow this down to a test case, but if you'd like me to send you some other log files I'd be happy to do that.

Thanks,
Tibor
answered by tibor (1.8k points)
0 votes
Hi Ohad,

I emailed you a testcase that reproduces the bug in patch 2. I assume you will be adding all these testcases your internal regression suite, right?

Thanks,
Tibor
answered by tibor (1.8k points)
0 votes
Hi Tibor
We sure add every bug to our tests...
Thank you for your efforts.
Users like you help us to make TypeMock a better product for all the users.
I will send the fix as soon as possible.
Thanks.
answered by ohad (35.4k points)
0 votes
Hi Tibor
I sent you the fix.
Waiting for your answer ... :shock:
answered by ohad (35.4k points)
...