65.9K
CodeProject 正在变化。 阅读更多。
Home

NetCase - 使用 .NET 中的元数据编程实现自动化测试用例 API

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.53/5 (6投票s)

2005年5月29日

3分钟阅读

viewsIcon

31086

downloadIcon

233

NetCase 是一个用于 .NET 中测试用例自动化的 API。

引言

本文通过一个名为 NetCase 的自动化测试 API 向新手介绍 Microsoft .NET 中的元数据编程。 尽管有很多类似的测试自动化资源(可能更高级),但这仍然是一个非常简单的测试 API,是我为了尝试 .NET 中的元数据编程而开发的。

元数据编程

元数据是指关于数据的数据,因此它是实际数据的两层间接。在现代编程语言(如 .NET 语言)中,元数据可用于获取有关编程语言实体(如类、方法等)的信息,然后检索此信息并对代码执行一些有用的操作。 Microsoft .NET framework SDK 包含 System.Reflection 命名空间,其中包含用于处理元数据的有用类。

NetCase 简介

NetCase 是我为在 .NET 中制作的测试自动化 API 起的名字,用于测试我编写的代码。 它类似于 Java 中的 JUnit 和 .NET 中的 NUnit。 我创建它纯粹是为了测试我在 .NET 中的元数据编程能力。 因此,可以为软件编写测试用例,并使用 NetCase 执行这些测试用例并查看结果。

编写 NetCase 测试用例

为了在 NetCase 中编写测试用例,必须从 NetCase.TestCase 类派生一个类。 TestCase 类具有以下方法

  • 初始化

    此方法在执行每个测试用例之前调用。

  • 最终化

    此方法在执行每个测试用例之后调用。

  • 断言(Assert)

    断言一个布尔条件。

可以看出,可以重写 Initialize 以在运行每个测试用例之前提供初始化代码,并且可以重写 Finalize 以提供清理代码。 可以在每个测试用例结束时测试断言条件以确定测试结果。 如果断言失败,则会抛出 TestFailedException 类型的异常。 以下是一个简单的测试用例方法示例,用于测试两个数字的二进制运算加法

[TestCase]
  public void Addition()
  {
     A = 2;
     B = 3;
     Assert((A+B) == 5, true);
  }

可以看出,测试用例方法用属性 [TestCase] 标记。 这有助于 NetCase 区分普通方法和测试用例方法。 这是一个简单的元数据示例。 测试用例也可以是负面的,例如

[TestCase(false)]
  public void Division()
  {
     A = 10;
     B = 1;
     Assert(float.IsInfinity(A/B), true);
  }

负面测试用例将 false 值传递给 [TestCase] 属性(默认情况下,测试用例是正面的)。 一旦从 NetCase.TestCase 类派生了一个类,就可以将其传递给 NetCase.TestCaseSuite 类的 RunTestCase 方法以执行。 RunTestCase 是一个静态方法,它执行包含在 TestCase 派生类中的测试用例,并返回 ClassTestResult 类型的对象。 以下是 ClassTestResult 结构的定义

public struct ClassTestResult
 {
    public TestResult [] SuccessfulTests;
    public TestResult [] UnSuccessfulTests;
 }

因此,调用者可以获取有关测试结果的信息。 请注意,负面测试用例的失败被认为是成功。 目前,我正在添加一个 Microsoft Visual Studio .NET 插件来显示测试结果,我将在完成后立即更新项目文件。

那么元数据编程在哪里呢?

NetCase.TestCaseSuite 类的 RunTestCase 方法的源代码包含用于处理测试方法的元数据代码。 该代码检查测试方法的正确格式并执行它们。

public static ClassTestResult RunTestCase(TestCase Case)
{
    // Perform Sanity
    if (Case == null)
    {
        throw new NullReferenceException();
    }

    // Initialize The Case
    Case.Initialize();
    Type CaseType = Case.GetType();
    ClassTestResult Result = new ClassTestResult();
    ArrayList SuccessfulTests = new ArrayList();
    ArrayList UnSuccessfulTests = new ArrayList();

    // Execute All Methods Marked As Test Cases
    foreach (MethodInfo Info in CaseType.GetMethods())
    {
        // Check If The Method Has TestCaseAttribute
        // If So Execute It
        foreach (Attribute Attr in Attribute.GetCustomAttributes(Info))
        {
            if (Attr.GetType() == typeof(TestCaseAttribute))
            {   
                try
                {
                    if ((Info.GetParameters().Length != 0)|| 
                       (Info.ReturnType != typeof(void))||
                       (!Info.IsPublic))
                    {
                        break;
                    }
                    // Positive Test Case
                    if (!((TestCaseAttribute)Attr).IsNegativeCase)
                    {
                        Info.Invoke(Case, null);
                        SuccessfulTests.Add(new TestResult(Info,true,false,null));
                    }
                    else
                    {
                        // Negative Test Case
                        try
                        {
                            Info.Invoke(Case, null);
                        }
                        catch (TargetInvocationException e)
                        {
                            // Test Case Threw Any Other Exception
                            // Than TestFailedException
                            if (e.InnerException.GetType() != 
                                       typeof(TestFailedException))
                            {
                                UnSuccessfulTests.Add(new TestResult(Info, 
                                            false,true,e.InnerException));
                            }
                            else
                            {
                                SuccessfulTests.Add(new TestResult(Info, 
                                           true,true,e.InnerException));
                            }
                            // Test Failed As Expected
                            continue;
                        }
                        // Negative Test Case Passed !
                        UnSuccessfulTests.Add(new TestResult(Info, false, 
                                       true, new TestFailedException()));
                    }
                }
                catch (System.Reflection.TargetInvocationException e)
                {
                    if (e.InnerException != null)
                    {
                        UnSuccessfulTests.Add(new TestResult(Info,false, 
                                               false,e.InnerException));
                    }
                    else
                    {
                        UnSuccessfulTests.Add(new TestResult(Info,false,false,e));
                    }
                }
            }
        }
        if (SuccessfulTests.Count > 0)
        {
            Result.SuccessfulTests = (TestResult[])
                   SuccessfulTests.ToArray(SuccessfulTests[0].GetType());
        }
        if (UnSuccessfulTests.Count > 0)
        {
            Result.UnSuccessfulTests = (TestResult[])
              UnSuccessfulTests.ToArray(UnSuccessfulTests[0].GetType());
        }
   }
   return Result;
}

暂时就这样! 在接下来的项目中,我将添加一个 Visual Studio .NET 加载项,它将显示一个带有测试进度和结果的工具栏。

© . All rights reserved.