views:

81

answers:

4

I'm trying to create a test class which organizes its test methods using inner classes. I would like for this class to be abstract with the ability to set a static property so this property can be injected. Here's an example of what I'm talking about:

[TestClass]
public abstract class BaseUnitTest
{
   public static string InjectedProperty;

   public static string GetInjectedString()
   {
      return InjectedProperty;
   }

   [TestClass]
   public class WhenFoo
   {
      [TestMethod]
      public void TestFoo()
      {
         string str = GetInjectedString();
      }
   }
}

[TestClass]
public class DeriverdUnitTest : BaseUnitTest
{
   [ClassInitialize]
   public void SetUp()
   {
      InjectedProperty = "Injected Property";
   }
}

However, I don't see a DerivedUnitTest+WhenFoo+TestFoo() class show up in my unit test view. I'm using Visual Studio 2010. I'm guessing when I override BaseUnitTest, I don't override its inner classes as well. I suppose I could make its inner classes abstract and override them later, but as the complexity of my test class increases this will get really annoying. Could somebody please explain why this is occuring and how I can fix it?

Thanks.

Edit:

I feel like I need to better explain my reasons for wanting to do this. We'd like to implement a testing standard which is very verbose in its naming. Therefore a test class would look something like this:

[TestClass]
public abstract class BaseUnitTest
{
   public static string InjectedProperty;

   public static string GetInjectedString()
   {
      return InjectedProperty;
   }

   [TestClass]
   public class WhenFooIsCalled
   {
      [TestClass]
      public class AndTheArgumentIsNull
      {
         [TestMethod]
         public void AnArgumentNullExceptionShouldBeThrown()
         {
            string str = GetInjectedString();
         }
      }
   }
}

The advantage of this is when you open up the test view in Visual Studio and display the method name and class name columns you get something that looks like this:

BaseUnitTest+WhenFooIsCalled+AndTheArgumentIsNull AnArgumentNullExceptionShouldBeThrown()

This makes it a lot easier to glance to tell what a failing test among a few hundred pass tests is supposed to do.

The main reason I want to be able to override the abstract BaseUnitTest is because when I do all of the tests which were contained in the BaseUnitTest are all added to the DerivedUnitTest and show up in the Test View in Visual Studio.

Thanks again.

A: 

Nested types don't work that way. You can't "override" types.

It's not clear what you're trying to achieve here, but I don't think it's going to work.

Jon Skeet
I'll guess I'll wait for 5 minutes for a real answer to show up.
Hans Passant
@Hans: I wasn't editing this... I really can't tell what's meant to be going on here, so I can't suggest anything more than going back to the drawing board. Maybe I'm just tired. If you have an idea, go for it :)
Jon Skeet
Okey-dokey, I'll give it a shot then.
Hans Passant
I edited my post with a better reason for wanting this behavior. Can you think of a better way to do what I'm trying to do?
helixed
@helixed: You haven't said why you want to do the verbose naming using nested classes rather than just a method name of "WhenFooIsCalled_AndTheArgumentIsNull_AnArgumentNullExceptionIsThrown". All the same information, but in one line instead of 8, and no attempt to make nested classes behave in a way which they just don't want to.
Jon Skeet
I guess the main reasoning was it logically divides tests and provides a clear location for exactly where everything should go in a test. I know that If I'm expecting a certain behavior for when Foo() is called and its argument is null, there's a clear spot that should be located. It also seems to make tests easer to navigate for somebody who didn't write them. If a method name changes, it's not necessary to change the name of every test method. Plus, method names are a lot shorter, so no horizontal scrolling is required. But it looks like you're right and I'm not going to be able to do this.
helixed
A: 

How about using a config file? For Example

   [TestClass]
   public class WhenFoo
   {
      [TestMethod]
      public void TestFoo()
      {
         string str = ConfigurationManager.AppSettings["WhenFooTestFooString"];
      }
   }
s_hewitt
The string I injected was only for an example. In a real situation I'd be injecting some other object, like an object registry.
helixed
+2  A: 

In the C# language, nested classes have no special relationship with the class in which they are nested. It is a completely different type. There is only one good reason you'd ever do this: you can declare the class private. Which helps you to create a little worker class to get a job done on behalf of the outer class, a class that is completely invisible from the outside. Very useful, you cannot otherwise declare a private class at outer class scope, the best you can do is internal.

What follows is that it in no way plays a role in the inheritance of the outer class. A class you derive from the outer has no visibility to the nested class inside the base class at all. Which was the intention, declaring it private was the reason to nest it in the first place.

Punt: if you need that class in the derived one just declare it internal or public.

Hans Passant
Thanks for the reply. I edited my post with a better reason for wanting this behavior. That's unfortunate about the way inner classes work in C#. Can you think of a way to mimic what I'm trying to do?
helixed
+1  A: 

You can accomplish the kind of rich, verbose, BDD-style test repriting with xUnit.NET and SubSpec. SubSpec is included in the xUnit.NET extras download these days. You can read more about SubSpec and BDD testing at the following article:

http://haacked.com/archive/2008/08/24/introducing-subspec.aspx

jrista