title: Is defining TestMethod's in test base classes not supported by MsTest?
body: <p>This question concerns a general unit test technique with a potentially very useful wide range of applicable scenarios. But it is easier to understand with an example to illustrate my question better.</p>
  
  <p>Let's say I want to test that all types that override <code>Equals()</code> does so correctly. Since <code>Equals()</code> is defined as virtual in <code>System.Object</code>, a wide range of types may change that behavior. Each type that does so, will have to have tests to make sure that the new behavior follows the implicit expectations of a caller of that method. Specifically for <code>Equals()</code>, if you override that method the new implementation must make sure that two equal objects also have equal hash codes, as defined by <code>System.Object.GetHashCode()</code>.</p>
  
  <p>Thus to enforce this, multiple test classes will be needed and they will all test for the same consistency of behavior across all these types.</p>
  
  <p>To avoid having to re-type all the TestMethods required to test such a type I instead define a base test class that looks like below, and have those test classes all inherit the same behavior test suite:</p>
  
  <pre><code>/// &lt;summary&gt;
  /// Test fixture base class for testing types that overrides Object.Equals()
  /// &lt;/summary&gt;
  /// &lt;typeparam name="T"&gt;The production type under test&lt;/typeparam&gt;
  public abstract class EqualsFixtureBase&lt;T&gt;
  {
      #region Equals tests
  
      protected static void CompareInstances(T inst1, T inst2, bool expectedEquals)
      {
          Assert.AreEqual(expectedEquals, inst1.Equals((T)inst2));
          Assert.AreEqual(expectedEquals, inst1.Equals((object)inst2));
          if (expectedEquals)
          {
              // equal instances MUST have identical hash codes
              // this is a part of the .NET Equals contract
              Assert.AreEqual(inst1.GetHashCode(), inst2.GetHashCode());
          }
          else
          {
              if (inst2 != null)
              {
                  Assert.AreNotEqual(inst1.GetHashCode(), inst2.GetHashCode());
              }
          }
      }
  
      /// &lt;summary&gt;
      /// Creates version 1 instance of the type under test, not 'Equal' to instance 2.
      /// &lt;/summary&gt;
      /// &lt;returns&gt;An instance created with properties 1.&lt;/returns&gt;
      protected abstract T CreateInstance1();
  
      /// &lt;summary&gt;
      /// Creates version 2 instance of the type under test, not 'Equal' to instance 1.
      /// &lt;/summary&gt;
      /// &lt;returns&gt;An instance created with properties 2.&lt;/returns&gt;
      protected abstract T CreateInstance2();
  
      /// &lt;summary&gt;
      /// Creates an instance equal to the version 1 instance, but not the identical
      /// same object.
      /// &lt;/summary&gt;
      /// &lt;returns&gt;An instance created with properties equal to instance 1.&lt;/returns&gt;
      protected abstract T CreateInstanceThatEqualsInstance1();
  
      [TestMethod]
      public void Equals_NullOrDefaultValueTypeInstance()
      {
          T instance = CreateInstance1();
          CompareInstances(instance, default(T), false);
      }
  
      [TestMethod]
      public void Equals_InstanceOfAnotherType()
      {
          T instance = CreateInstance1();
          Assert.IsFalse(instance.Equals(new object()));
      }
  
      [TestMethod]
      public void Equals_SameInstance()
      {
          T slot1 = CreateInstance1();
          CompareInstances(slot1, slot1, true);
      }
  
      [TestMethod]
      public void Equals_EqualInstances()
      {
          T slot1 = CreateInstance1();
          T slot2 = CreateInstanceThatEqualsInstance1();
          CompareInstances(slot1, slot2, true);
          CompareInstances(slot2, slot1, true);
      }
  
      [TestMethod]
      public void Equals_NonEqualInstances()
      {
          T slot1 = CreateInstance1();
          T slot2 = CreateInstance2();
          CompareInstances(slot1, slot2, false);
          CompareInstances(slot2, slot1, false);
      }
  
      #endregion Equals tests
  }
  </code></pre>
  
  <p>I can then reuse these TestMethods for each type overriding Equals(). For instance, this would be the test class definition for testing that the <code>System.String</code> type implements <code>Equals()</code> correctly.</p>
  
  <pre><code>[TestClass]
  public class ExampleOfAnEqualsTestFixture : EqualsFixtureBase&lt;string&gt;
  {
      [TestMethod]
      public void Foo()
      {
          Assert.IsTrue(true);
      }
  
      protected override string CreateInstance1()
      {
          return "FirstString";
      }
  
      protected override string CreateInstance2()
      {
          return "SecondString";
      }
  
      protected override string CreateInstanceThatEqualsInstance1()
      {
          return "FirstString";
      }
  }
  </code></pre>
  
  <p>This can also be extended further. For instance, for types that overload the == and != operators, a second abstract test base class can be defined (i.e. <code>EqualsOperatorsFixtureBase&lt;T&gt; : EqualsFixtureBase&lt;T&gt;</code>) that tests that the implementation of those operators are not only correct, but also consistent with the extended definitions of <code>Equals()</code> and <code>GetHashCode()</code>.</p>
  
  <p>I can do this using NUnit, but when using MsTest I get problems.</p>
  
  <p>a) Visual Studio 2010 only discovers the <code>Foo()</code> test method, not the inherited test methods so it can't run them. It seems the Visual Studio test loader does not walk the inheritance hierarchy of the test class.</p>
  
  <p>b) When I check in these types in TFS, TFS finds the abstract EqualsFixtureBase type and thinks it is a test class to be run. But since it can not be created, it can't run it and labels the tests in that type as inconclusive - which fails the test run, and thus the build (!).</p>
  
  <p>Is there a way to get around this, or is this a limitation of MsTest and Visual Studio?</p>
  
  <p>If so, is fixing this in the roadmap for VS/TFS ??</p>
  
  <p>This would be very useful, especially when testing production types that implement an interface, or are part of an inheritance hierarcy, where certain members have semantic 'contract type' properties or invariants - if that makes sense.</p>
  
  <p>Basically, not having support for this inhibits me from refactoring my test code to remove duplication.</p>
  
  <p>Thanks</p>
  
  <p>EDIT: I found <a href="http://blogs.msdn.com/b/nnaderi/archive/2007/02/01/mstest-vs-nunit-frameworks.aspx" rel="noreferrer">this link</a> to one of the MSDN blogs, it says the following</p>
  
  <blockquote>
    <p>"In Whidbey, support for test class inheritance was missing. In Nunit, it is fully supported. This will be rectified in Orcas."</p>
  </blockquote>
  
  <p>That was written over three years ago. Why has this not been added yet? I don't get it, there are legitimate reasons to have this and in my mind it would be a minor change. Or am I just not jumping the right hoops here?</p>