Friday, February 11, 2011

Convert string to C# code

Hi,

in the current NUnit version, I can parameterized TestFixture and instantiated it multiple times. E.g.:

[TestFixture("var1")]  
[TestFixture("var2")]  
[TestFixture("var3")]  
public class MyTestFixture  
{  
    private string var;  

    public MyTestFixture(string var)  
    {  
        this.var = var;  
    }  

    ...  

}  

This will instantiate the MyTestFixture 3 times with the argument parameter. My problem is the current NUnit doesn't have datasource feature for TextFixture attribute (only TestCaseSource). I need to instantiate the TestFixture based on the data input, and each TestFixture has a different sets of test case data input. No problem with the Test case data driven, thanks to the TestCaseSource. But how can I do this for the TestFixture attribute?

My idea is to generate the TestFixture attribute on the fly then change it to code string and insert into the test code, e.g.: something like this:

ConvertToCode(GenerateTestFixture());  
public class MyTestFixture  
{  
   ...  
}  

How can I do this? Or are there a better way?

Thank you very much for your help.

Best regards,
Edward

  • Creating attributes for your method on the fly is possible but hard. You're better off finding another approach.

    Attributes (e.g. [TestFixture]) of the kind you have are read by the compiler when your code is compiled and inserted in to your code automatically.

    To generate your own attributes for classes you'll need to use something like Reflection.Emit to modify generated assemblies as a post-build step for the project. This is like writing assembly language directly (you'd be creating MSIL) which might be fun but is not easy and would make your code very hard to maintain!

    An alternative approach might be to have an enum control the test cases, and have a method that checks the enum and returns the appropriate data:

    public enum TestController
    {
        Value1,
        Value2,
        Value3
    }
    
    [TestFixture(TestController.Value1)]   
    [TestFixture(TestController.Value2)]   
    [TestFixture(TestController.Value3)]   
    public class MyTestFixture   
    {   
        public MyTestFixture(TestController testController)   
        {   
            var dataForTest = GetDataForTest(testController);
        }   
    
        ...   
    
    }   
    

    The method GetDataForTest() would then have some kind of switch statement to generate the data.

    An alternative approach might be to use a type rather than an enum, then instantiate the type in the GetDataForTest() method and call a factory method - but I think that might be a bit overcomplicated.

    Edward : Thank you very much Jeremy. The thing is TestFixture is data-driven, so I wouldn't know in advance how many value there will be. Would the other approach works for data driven TestFixture? If yes, can you please give me a short sample? Again thank you very much for your help. Best regards, Edward
    Jeremy McGee : If you don't know how many there will be then I don't think it will be possible to have seperate tests for each data item. Rather, you'll need to have one test that tests all data items.
    Edward : Actually the test already exist with one test cases test all data items, we also have custom test result to generate result for each data item. But since NUnit 2.5 support data-driven I was tasked to convert the existing test the UNit data driven. This has some benefits over the existing test, such as look better in the UI, can run one test, etc.I can just use the TestCaseSource, the problem is the test name become very long with a lot of duplicates as test cases kind of hierarchical. I think I'll give the Reflection.Emit approach a try. Thank you very much for your help. Best regards, Edward
    Jeremy McGee : Reflection.Emit here is most certainly non-trivial - you're essentially replicating tools like PostSharp that do aspect-oriented programming.

0 comments:

Post a Comment