代码之家  ›  专栏  ›  技术社区  ›  chilltemp

我如何使用一组定制的参数重复运行.NET单元测试?

  •  3
  • chilltemp  · 技术社区  · 14 年前

    我有一个单元测试方法需要几个参数。我想对笛卡尔的每个可能值运行一次这个测试,每个参数都有一个预定义的列表。我设想参数可以通过测试上下文传入,但我不想连接到外部数据库。

    例如:如果我有两个具有以下可能值的参数,测试将执行6次(顺序无关紧要)。(伪码)

    p1 = { 1, 5, 10 }
    p2 = { "blue", "red" }
    
    test 1: ( 1, "red" )
    test 2: ( 5, "red" )
    test 3: ( 10, "red" )
    test 4: ( 1, "blue" )
    test 5: ( 5, "blue" )
    test 6: ( 10, "blue" )
    

    注意:我使用的是内置的Visual Studio 2010单元测试,而不是Nunit或其他许多单元测试框架之一。

    编辑:

    我将可能的值作为枚举存储在测试类中,但是使用数组也是合理的。我的目标是自动化源枚举/数组和实际测试之间的链接。虽然我的样本只有2个参数,6个排列,但实际集合要大得多。我不想跳过一个场景,只是因为我在手动转换中遗漏了一些内容。

    5 回复  |  直到 13 年前
        1
  •  2
  •   Vivian River    14 年前

    您的问题的答案是:您可以使用“数据驱动测试”。可以将值存储在逗号分隔的值文件、XML文件或SQL数据库文件中。我用的是vs2k8,所以你使用vs2k10的过程可能有点不同。

    首先,用测试数据创建一个文件。如果创建一个csv文件,它可能看起来像

    PARAM1,PARAM2
    1,蓝色
    1,红色
    5,蓝色
    5,红色
    10,红色
    10,蓝色

    转到“测试视图”,选择要使用数据的测试。在“属性”中,单击“数据连接字符串”旁边的省略号点。指定文件。

    现在,在单元测试代码中,您将从文件中指定数据为 testContext.DataRow("param1") testContext.DataRow("param2") .

    当您运行测试时,您将获得测试运行所使用的每个数据行的测试结果。多方便啊!

    更新 如果要自动使用作为枚举保留的参数的笛卡尔积,则可能要使用嵌套for循环,例如

    Dim testsults as dictionary(三元组的,字符串的)
    在foocollection中,每个x作为foo
    在BarCollection中为每个Y添加条形图
    对于FoobarCollection中的每个z作为Foobar 尝试 测试码
    testsults.add(new triplet(x,y,z),“pass”)。
    作为异常捕获Ex
    test results.add(new triplet(x,y,z),“错误:”+例如toString())
    最后尝试

        2
  •  4
  •   Sanjay Mohan    13 年前

    你可以使用像.NET中的galio这样的工具来实现这一点。

    [Test]
    [Row(0, 0)]
    [Row(1, 1)]
    public void Lower_bounds(int x, int expectedResult)
    {
       int result = Fibonacci.Calculate(x);
       Assert.AreEqual(expectedResult, result);
    }
    

    提示1:您可以通过学习galio中的[factory]属性来进一步扩展这一点。 提示2:配对有助于生成组合

    感谢Jeroen编辑代码并提供支持

        3
  •  3
  •   Community c0D3l0g1c    7 年前

    对于这种类型的测试,一定要考虑 Pex 你自己的。

    但是,为什么不创建一个外部测试 generates all the combinations 从运行时的集合中调用每个组合的测试方法一次?

        4
  •  0
  •   Jeff Schumacher    14 年前

    正如@hemp提到的,您可以使用一个外部测试来生成枚举的所有排列。班上 http://www.codeproject.com/KB/recipes/Combinatorics.aspx 看起来很有趣。

    然而,测试所有可能的组合仅仅是一个健全的检查吗?对我来说,这是一种代码味道,我会寻找边缘案例,而不是让运行排列的测试运行时间陷入困境。只是一个想法。:)

        5
  •  0
  •   chilltemp    14 年前

    @新星使用数据驱动的想法是最好的解决方案。我将它与T4脚本结合使用,生成一个包含笛卡尔枚举的csv。这是供您参考的脚本(使用 T4 Toolbox )

    <#@ template debug="false" hostspecific="true" language="C#" #>
    <#@ output extension=".csv" #>
    <#@ include file="T4Toolbox.tt" #>
    <#@ import namespace="EnvDTE" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#
        List<CodeEnum> enums = GetEnums("TestClass.cs");    
        bool first = true;
    
        // Header
        foreach(CodeEnum e in enums)
        {
            if(first)
                first = false;
            else
                Write(",");
    
            Write(e.Name);
        }
        WriteLine("");
    
        // Data
        WriteData(enums);
    #>
    <#+
        private void WriteData(List<CodeEnum> enums)
        {
            WriteData(enums, new string[enums.Count], 0);
        }
    
        private void WriteData(List<CodeEnum> enums, string[] values, int level)
        {   
            foreach (CodeElement element in enums[level].Children)
            {
                values[level] = element.Name;
    
                if(level + 1 < enums.Count)
                {
                    WriteData(enums, values, level + 1);
                }
                else
                {
                    WriteLine(string.Join(",", values));
                }
            }
        }
    
        private List<CodeEnum> GetEnums(string enumFile)
        {
            ProjectItem projectItem = TransformationContext.FindProjectItem(enumFile);
            FileCodeModel codeModel = projectItem.FileCodeModel;
            return FindEnums(codeModel.CodeElements);
        }
    
        private List<CodeEnum> FindEnums(CodeElements elements)
        {
            List<CodeEnum> enums = new List<CodeEnum>();
    
            FindEnums(elements, enums);
    
            return enums.Count == 0
                ? null
                : enums;
        }
    
        private void FindEnums(CodeElements elements, List<CodeEnum> enums)
        {
            foreach (CodeElement element in elements)
            {
                if (element is CodeEnum)
                    enums.Add((CodeEnum)element);
    
                FindEnums(element.Children, enums);
            }
        }
    #>