51Testing软件测试论坛

标题: 转贴-用反射与自定义属性实现单元测试工具(NUnit) [打印本页]

作者: sincky    时间: 2006-1-12 23:52
标题: 转贴-用反射与自定义属性实现单元测试工具(NUnit)
用反射与自定义属性实现单元测试工具(NUnit)
反射是.Net、Java等托管语言区别于传统语言(C++,Delphi等)的一大特性,通过反射我们可以动态的创建类,调用方法等。考虑了一下NUnit的功能,觉得利用这个特性也可以做一个出来,于是就动手做了个练习,基本达到了效果,模拟NUnit提供框架如下:

//=======================================

UnitDll (模拟nunit.framework)

[AttributeUsage(AttributeTargets.Class)]
public class TestFixtureAttribute : System.Attribute
{
  public TestFixtureAttribute()
  {
  }
}

[AttributeUsage(AttributeTargets.Method)]
public class Test : System.Attribute
{
  public Test()
  {
  }
}

// 以上为两个Attribute,标识要测试的类与方法

/// <summary>
/// Assert的异常类,用来抛出Assert异常
/// </summary>
public class VAssertException : System.ApplicationException
{
  
  private string m_expstr  = "";

  public VAssertException()
  {
  }

  public VAssertException(string err)
  {
     m_expstr = err;
  }

  public string ExceptionStr
  {
   get   {    return m_expstr;   }
   set   {    m_expstr = value;   }
  }
}

// 以上为异常类,Assert失败的时候扔出异常

/// <summary>
/// 用于单元测试的Assert类
/// </summary>
public class Assert
{
  public Assert()
  {
  }

  public static void AreEqual(object expected, object actual)
  {

   if (expected != actual)
   {
    string str = "expected is:"+expected+" but actual is:"+actual;
   
    VAssertException e = new VAssertException(str);
    throw e;
   }
  }
}

// 以上为提供测试方法类,提供AreEqual,模拟NUnit提供的Assert类

//===========================================================

TestDll : 要进行单元测试的类,使用上面提供的UnitDll

/// <summary>
/// // 要进行单元测试的类
/// </summary>
[TestFixture]                                 // 标识为要进行测试的类
public class VUnitTest
{
  public VUnitTest()
  {
   System.Console.WriteLine("Now the Unit Test Class create");
  }

  [Test]
  public void TestMethod()
  {
   System.Console.WriteLine("This is a unit test method");
   Assert.AreEqual(1,2);                                // 使用UnitDll提供的Assert类进行单元测试
  }

//==================================

UnitTest.exe   模拟NUnit.exe,提供的一个win form,主要以treeview的方式展现。

界面的代码比较简单就不提供了,提供几段关键的反射与调用的代码:

  private void LoadDll()
  {
   this.treeView1.Nodes.Clear();
   rootnode = this.treeView1.Nodes.Add(openFileDialog1.FileName);
     
   a = Assembly.LoadFrom(openFileDialog1.FileName);

   Type [] types = a.GetTypes();

   foreach (Type type in types)
   {
    object [] attributes = type.GetCustomAttributes(false);

    foreach (object obj in attributes)
    {
     // 得到了带有测试注明信息的类
     if (obj.GetType() == typeof(TestFixtureAttribute))
     {
      // 增加一个类名
      TreeNode node = rootnode.Nodes.Add(type.Name);

      MethodInfo [] methods = type.GetMethods();

      foreach (MethodInfo method in methods)
      {
       object [] methodattributes = method.GetCustomAttributes(false);

       foreach (object objmehtod in methodattributes)
       {
        if (objmehtod.GetType() == typeof(Test))
        {
         node.Nodes.Add(method.Name);
        }
       }

      }

     }

    }

   }

   this.treeView1.ExpandAll();

  }
// 上面的代码比较简单,利用反射得到需要进行测试的类与方法,并展现在一个treeview中

    object obj = Activator.CreateInstance(type);

    MethodInfo method = type.GetMethod(this.treeView1.SelectedNode.Text);
    if (method == null)
    {
     MessageBox.Show("方法不匹配");
     return;
    }

    object [] parameters = new object[0];
    method.Invoke(obj,parameters);

    this.listBox1.Items.Insert(0,"ok");
    SetLabel(true);

   }
   catch(System.Reflection.TargetInvocationException ex)
   {
    string str = ex.ToString();

    Exception exc = ex.InnerException;

    if (exc.GetType() == typeof(VAssertException))
    {
     VAssertException objex = (VAssertException)exc;

     string sstr = objex.ExceptionStr;
     this.listBox1.Items.Insert(0,sstr);

     this.listBox1.Items.Insert(0,exc.StackTrace);
     this.listBox1.Items.Insert(0,ex.StackTrace);

     SetLabel(false);

    }

// 上面的代码相当于NUnit界面中的run,也是比较核心的一段

// 主要就是通过创建要测试的类(CreateInstance),然后调用Invoke

// 判断是否断言失败(是否有自定义的异常扔出),有的话测试失败,把失败信息显示在界面即可

//======================================================

小结: 基本可以达到NUnit的效果,但是业务与界面的代码混在一起,没有很好的隔离,

比较好的方法是把反射这块封起来,提供一个接口给界面反应即可。

请大家多提意见
作者: ecust    时间: 2006-4-4 15:18
我顶!!!!!!!!




欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2