views:

1522

answers:

5

These days, i came across a problem with Team System Unit Testing. I found that the automatically created accessor class ignores generic constraints - at least in the following case:

Assume you have the following class:

namespace MyLibrary
{
 public class MyClass
 {
  public Nullable<T> MyMethod<T>(string s) where T : struct
  {
   return (T)Enum.Parse(typeof(T), s, true);
  }
 }
}

If you want to test MyMethod, you can create a test project with the following test method:

public enum TestEnum { Item1, Item2, Item3 }

[TestMethod()]
public void MyMethodTest()
{
 MyClass c = new MyClass();
 PrivateObject po = new PrivateObject(c);
 MyClass_Accessor target = new MyClass_Accessor(po);

 // The following line produces the following error:
 // Unit Test Adapter threw exception: GenericArguments[0], 'T', on
 // 'System.Nullable`1[T]' violates the constraint of type parameter 'T'..
 TestEnum? e1 = target.MyMethod<TestEnum>("item2");

 // The following line works great but does not work for testing private methods.
 TestEnum? e2 = c.MyMethod<TestEnum>("item2");
}

Running the test will fail with the error mentioned in the comment of the snippet above. The problem is the accessor class created by Visual Studio. If you go into it, you will come up to the following code:

namespace MyLibrary
{
 [Shadowing("MyLibrary.MyClass")]
 public class MyClass_Accessor : BaseShadow
 {
  protected static PrivateType m_privateType;

  [Shadowing(".ctor@0")]
  public MyClass_Accessor();
  public MyClass_Accessor(PrivateObject __p1);
  public static PrivateType ShadowedType { get; }
  public static MyClass_Accessor AttachShadow(object __p1);

  [Shadowing("MyMethod@1")]
  public T? MyMethod(string s);
 }
}

As you can see, there is no constraint for the generic type parameter of the MyMethod method.

Is that a bug? Is that by design? Who knows how to work around that problem?

+1  A: 

I vote bug. I don't see how this could be by design.

Will
+1  A: 

I didn't verify everything, but it looks like the call to:

TestEnum? e1 = target.MyMethod("item2");

uses type inference to determine the generic type param T. Try calling the method differently in the test if possible:

TestEnum? e1 = target.MyMethod<TestEnum>("item2");

That may yield different results.

Hope that helps!

Zachary Yates
A: 

Search for unit tests with generics on msdn. This is a known limitation. Vote for a resolution on Microsoft Connect, as it is definately needs resolving.

+1  A: 

Here is a similar issue on connect for reference. https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=324473&amp;wa=wsignin1.0

Josh Heyse
"Closed as Won't Fix"? Fantastic.
Tullo
A: 

Looks like a bug. The workaround would be to change the method to internal and add [assembly: InternalsVisibleTo("MyLibrary.Test")] to the assembly containing class under test.

This would be my preferred way of testing non-public methods as it produces much cleaner looking unit tests.

Igor Zevaka