In the past, for each class library project we create in Visual Studio, we have maintained separate unit test and integration test projects. This has allowed us to easily configure continuous integration with TFS to run a given project’s unit tests on check-in and run the full suite of unit and integration tests on a nightly build.
With the introduction of Visual Studio 2010, build types now can filter tests based on test categories.
For example, I can categorize a given test as a unit test by doing the following:
[TestClass]
public class Test
{
[TestMethod]
[TestCategory("UnitTest")]
public void IsValid_returns_false_when_quantity_large()
{
}
}
This allows us to consolidate all tests into one project and distinguish by categories. The only issue is that these categories are based on strings that the developer must type, and this can create inconsistencies using magic strings which may not be noticed during the course of development.
In order to get around this, another option is to create your own custom test category attributes that return the proper string. Microsoft has provided a base class, TestCategoryBaseAttribute for this very purpose.
public class UnitTestAttribute : TestCategoryBaseAttribute
{
public UnitTestAttribute()
{}
public override IList<string> TestCategories
{
get { return new List<string> {"UnitTest"}; }
}
}
By overriding the TestCategories property, you can return the appropriate string(s) that represent this classification. In this case, we are returning the same string that the previous test category provided.
In order to use this attribute, you merely need to add it to a given test method like so.
[TestClass]
public class Test
{
[TestMethod]
[UnitTest]
public void IsValid_returns_false_when_quantity_large()
{
}
}
With this kind of flexibility, if you had a limited list of attributes that you wanted to provide to developers, you could also create an enum type and pass that into the constructor of the custom test category attribute.
Just create an enum type.
public enum Category : int
{
UnitTest = 0,
IntegrationTest = 1
}
Then, create the attribute using the enum as a constructor parameter.
public class TestCategoryAttribute : TestCategoryBaseAttribute
{
private TestCategory _category;
public TestCategoryAttribute(TestCategory category)
{
_category = category;
}
public override IList<string> TestCategories
{
get
{
var value = Enum.GetName(typeof (TestCategory), _category);
return new List<string>{ value };
}
}
}
To use the new attribute, you would do the following.
[TestClass]
public class Test
{
[TestMethod]
[TestCategory(Category.UnitTest)]
public void IsValid_returns_false_when_quantity_large()
{
}
}
Hope this helps!