First off, I want to say that up until now, I have really enjoyed using Mighty Moose. Don't get me wrong, I don't dislike using Mighty Moose at this point, I'm just a bit frustrated that it's not working correctly. But, as with all software, there are bound to be bugs; and it looks like I was the unfortunate soul to find one. Anyway, keep up the good work, I really like the tool.
So, let me explain about the "bug" that I found.
I've been playing around with the idea of having test "contexts", implemented as nested test classes, in order to keep the setup methods small and focused on only containing the data needed for a set of tests. I'm writing some code to implement a Category class. The invariants of the contract class are that a category name cannot be null or whitespace, a category parent cannot be null, and a subcategory of the category cannot be added if the subcategory is a null object or the Null Object Pattern Category.None. Here's a partial listing of the test class that demonstrates the issue:
[TestClass]
public class CategoryTests
{
private string PARENT;
private string CHILD;
[TestInitialize]
public void InitializeCategoryTestsContext()
{
PARENT = "Parent";
CHILD = "Child";
}
[TestMethod]
[ExpectedException(typeof(InvalidCategoryNameException))]
public void Cannot_create_a_Category_with_a_null_string_for_a_name()
{
// I'm trying out different stuff--a factory may indeed not be appropriate; but my code architecture is not at issue here, though the execution of the tests are...so bear with me. :)
CategoryFactory.CreateCategory(null);
}
[TestClass]
public class ParentCategoryContext : CategoryTests
{
private Category parent;
[TestInitialize]
public void InitializeParentCategoryContext()
{
parent = CategoryFactory.CreateCategory(PARENT);
}
[TestMethod]
public void A_top_level_category_returns_its_name_when_ToString_is_called()
{
Assert.AreEqual(PARENT, parent.ToString()); // This passes in VS when using MSTest test runner, but when run using AutoTest.Net, PARENT is null, causing the test to fail an invariant.
}
}
}
Now, since the field PARENT is never used in the outer test class, yes, I could have put the field in the inner class (actually, I should do that, regardless, but when I first wrote the test, I planned on using the field in the outer class. Not only that, if the classes were instantiated correctly, the field should have been inherited by the inner class anyway, making this whole diatribe extraneous to begin with :) ). When I do put the PARENT field in the inner class, the tests in that class pass as expected:
[TestClass]
public class CategoryTests
{
private string CHILD;
[TestInitialize]
public void InitializeCategoryTestsContext()
{
CHILD = "Child";
}
[TestMethod]
[ExpectedException(typeof(InvalidCategoryNameException))]
public void Cannot_create_a_Category_with_a_null_string_for_a_name()
{
// I'm trying out different stuff--a factory may indeed not be appropriate; but my code architecture is not at issue here, though the execution of the tests are...so bear with me. :)
CategoryFactory.CreateCategory(null);
}
[TestClass]
public class ParentCategoryContext : CategoryTests
{
private string PARENT;
private Category parent;
[TestInitialize]
public void InitializeParentCategoryContext()
{
PARENT = "Parent";
parent = CategoryFactory.CreateCategory(PARENT);
}
[TestMethod]
public void A_top_level_category_returns_its_name_when_ToString_is_called()
{
Assert.AreEqual(PARENT, parent.ToString()); // This passes in VS and in AutoTest.Net when PARENT is declared and defined in this class.
}
}
}
It seems like AutoTest is just finding all classes marked with the TestClassAttribute without taking into consideration it's scope (e.g. that it may be nested in another class) and properly instantiating it based on its scope.
While in this instance, I was able to "fix" the failing tests so that they pass, this was a very easy scenario--the field in question was not used in the outer class. Had it been a situation where the field was used in both the outer and inner class, the inner tests would fail (or, I'd have to declare and define the same fields in the inner class, which is exactly what I'm trying to avoid; or, a third option, declare new classes for each "context", repeating the required setup code from other contexts where needed in order to ensure all tests pass--which one might argue could be cleaner, despite the code duplication--no "deep" nesting and no "hidden" setups). In any event, invariably, some will choose the nesting style I have chosen (at least, for now).
Anyway, as I said in my intro, keep up the good work. I really like the tool. Thanks again!