Partager via


Use Custom Attributes to initialize test environments

Some tests can be quite complex, perhaps having prerequisites that consist of various steps, querying initial conditions, loading test data, etc.

You can use Attributes to specify various test configurations.

The sample below shows how to create your own attribute class and how to retrieve and use it in various parts of your code.

I use this technique in conjunction with an XML config file (using System.Configuration.ConfigurationManager) to specify configurations that are global to all tests, which can be overridden at the class or method level.

Start Visual Studio:

File->New->Project->C#-> Test->Unit Test Project

(Works with Temporary projects too )

Open the Test Explorer: Menu->Test->Windows->Test Explorer

Put your cursor in TestMethod1, then hit Ctrl-R T (not ctrl-R Ctrl-T) to run the test. Since there’s no code in the test yet, the test will pass.

Now modify your test by adding this line:

                Assert.Fail(“This is a failed test”);

Now hit Ctrl-R L  to repeat the last test run. The test fails.

Ctrl-R L is my favorite key combination: I love Test Driven Development

See also:

Automatic tests protect your code

 

<Code>

 using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CSTest
{
  // indicate this attr is valid only on a method or class
  // and that multiple attributes 
  //  on the same object are not allowed
  [AttributeUsage(validOn: AttributeTargets.Method |
    AttributeTargets.Class, AllowMultiple = false)]
  public class MyCustomAttribute : Attribute
  {
    public string SomeProperty { get; set; }
    public void DoTheWork()
    {
      //here we can do the work requireed
      // e.g. create a teset environment for the test
    }
  }

  [TestClass]
  [MyCustom(SomeProperty = "classLevel")]
  public class UnitTest1
  {
    public TestContext TestContext { get; set; } // the test infrastructure sets this
    [TestInitialize]
    public void ThisMethodNameDoesntMatter()
    {
//      Assert.Fail("in TestInitialize");
      DoTheTesting();
    }

    [TestMethod]
    [MyCustom(SomeProperty = "methLevel")]
    public void TestMethod1()
    {
      DoTheTesting();
    }
    private void DoTheTesting()
    {
      Assert.IsTrue(this.TestContext != null);
      Assert.IsTrue(this.TestContext.TestName == "TestMethod1");
      // get a MethodInfo for this test method
      var thisMethod = this.GetType().GetMethod(this.TestContext.TestName);
      var thisClass = thisMethod.DeclaringType;
      Assert.IsTrue(thisClass.Name == "UnitTest1");
      var custAttr = (MyCustomAttribute)thisMethod.
          GetCustomAttributes(
            typeof(MyCustomAttribute),
            inherit: false
          ).
        FirstOrDefault();
      Assert.IsTrue(custAttr != null);
      Assert.IsTrue(custAttr.SomeProperty == "methLevel");

      custAttr = (MyCustomAttribute)thisClass.
        GetCustomAttributes(
          typeof(MyCustomAttribute),
          inherit: false
        ).
        FirstOrDefault();
      Assert.IsTrue(custAttr != null);
      Assert.IsTrue(custAttr.SomeProperty == "classLevel");

      // now if both class level and method level, let's default 
      //   to method level
      custAttr = (MyCustomAttribute)thisMethod.
        GetCustomAttributes(
          typeof(MyCustomAttribute),
          inherit: false
        ).
        Union(thisClass.
          GetCustomAttributes(
            typeof(MyCustomAttribute),
            inherit: false
          )
        ).
        FirstOrDefault();
      Assert.IsTrue(custAttr != null);
      Assert.IsTrue(custAttr.SomeProperty == "methLevel");

      custAttr.DoTheWork();

      //Assert.Fail("This is a failed test");
    }
  }
}

</Code>