【问题标题】:Can nunit-console list all test names in a test fixture?nunit-console 可以列出测试夹具中的所有测试名称吗?
【发布时间】:2012-02-20 22:21:26
【问题描述】:

我想在它们运行之前报告它们,并且可以选择通过 shell 脚本运行单个测试而不管理类别。我们有一些非托管代码可能会使进程处于不良状态,有时很乐意在每次 nunit-console 运行时单独运行每个测试。

【问题讨论】:

  • nunit-console MyAssembly.dll /labels 将在运行时显示所有测试,但我认为您想要的是事先获取该列表然后提示用户(或将它们添加到 /runlist=文件)?不想使用类别的理由是什么?
  • 我们需要他们提前,正确的。这里的关键是我们想一次运行一个,即一次又一次地运行 nunit-console 本身,每次测试一次。我们更改了组件,因此我们不再需要这样做了,但我仍然很惊讶没有看到关于此的答案。
  • 如果这对你来说仍然是个问题,我很想看看使用他们的 EventListener 类(参见imistaken.blogspot.co.uk/2009/03/… 的例子)看看你是否可以通过这种方式获得列表,但是将依赖于能够抑制测试的实际运行,这是我不尝试就不会知道的事情。

标签: nunit unmanaged nunit-console


【解决方案1】:

nunit-console 似乎仍然不支持此选项。然而,使用反射获取测试用例列表相当简单。在一个非常基本的级别上,您需要具有适当的[Test]/[TestFixture] 属性的任何public class 的所有public 方法的列表。根据测试的结构,您可能需要进行额外的过滤,例如删除任何标记有[Ignore] 属性的测试或考虑基类中的测试方法。

在基本层面上,代码如下所示:

// Load the assembly containing your fixtures
Assembly a = Assembly.LoadFrom(assemblyName);

// Foreach public class that is a TestFixture and not Ignored
foreach (var c in a.GetTypes()
                   .Where(x=>x.IsPublic 
                   && (x.GetCustomAttributes(typeof(NUnit.Framework.TestFixtureAttribute)).Count() > 0)
                   && (x.GetCustomAttributes(typeof(NUnit.Framework.IgnoreAttribute)).Count() ==0))) 
{
    // For each public method that is a Test and not Ignored
    foreach (var m in c.GetMethods()
                       .Where(x=>x.IsPublic
                       && (x.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute)).Count() > 0)
                       && (x.GetCustomAttributes(typeof(NUnit.Framework.IgnoreAttribute)).Count() ==0))) 
    {
        // Print out the test name
        Console.WriteLine("{0}.{1}", c.ToString(), m.Name);
        // Alternately, print out the command line to run test case using nunit-console
        //Console.WriteLine("nunit-console /run:{0}.{1} {2}", c.ToString(), m.Name, assemblyName);
    }
}

如果您只想要来自特定 TestFixture 的测试方法,显然可以稍微简化一下。

正如 cmets 中所说,如果您需要注意其他 NUnit 属性,例如 TestCase 和 TestCaseSource,这会变得有点复杂。我修改了下面的代码以支持这些属性的一些功能。

static void PrintTestNames(string assemblyName) {
    Assembly assembly = Assembly.LoadFrom(assemblyName);

    foreach (var fixture in assembly.GetTypes().Where(x => x.IsPublic
                                      && (x.GetCustomAttributes(typeof(TestFixtureAttribute)).Count() > 0)
                                      && (x.GetCustomAttributes(typeof(IgnoreAttribute)).Count() == 0))) {
        foreach(var method in fixture.GetMethods().Where(x=>x.IsPublic
            && (x.GetCustomAttributes(typeof(IgnoreAttribute)).Count() == 0)
            && ((x.GetCustomAttributes(typeof(TestAttribute)).Count() > 0)
                || (x.GetCustomAttributes(typeof(TestCaseAttribute)).Count() > 0)
                || (x.GetCustomAttributes(typeof(TestCaseSourceAttribute)).Count() > 0))
            )) {
            var testAttributes = method.GetCustomAttributes(typeof(TestAttribute)) as IEnumerable<TestAttribute>;
            var caseAttributes = method.GetCustomAttributes(typeof(TestCaseAttribute)) as IEnumerable<TestCaseAttribute>;
            var caseSourceAttributes = method.GetCustomAttributes(typeof(TestCaseSourceAttribute)) as IEnumerable<TestCaseSourceAttribute>;

            if (caseAttributes.Count() > 0) {
                foreach(var testCase in caseAttributes) {
                    if (!string.IsNullOrEmpty(testCase.TestName)) {
                        PrintTestName(fixture.ToString(), testCase.TestName);
                    }
                    else {
                        string arguments = ExtractArguments(testCase.Arguments);
                        PrintTestName(fixture.ToString(), method.Name + arguments);
                    }
                }
            }
            else if (caseSourceAttributes.Count() > 0) {
                foreach (var testCase in caseSourceAttributes) {
                    var sourceName = testCase.SourceName;
                    if (!string.IsNullOrEmpty(sourceName)) {
                        var staticMember = fixture.GetField(sourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
                        var instanceMember = fixture.GetField(sourceName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
                        var staticMethodMember = fixture.GetMethod(sourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
                        var instanceMethodMember = fixture.GetMethod(sourceName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
                        var staticPropMember = fixture.GetProperty(sourceName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
                        var instancePropMember = fixture.GetProperty(sourceName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);


                        IEnumerable memberValues;

                        if (null != staticMember) {
                            memberValues = staticMember.GetValue(null) as IEnumerable;
                        }
                        else if (null != instanceMember) {
                            var instance = Activator.CreateInstance(fixture);
                            memberValues = instanceMember.GetValue(instance) as IEnumerable;
                        } else if(null != staticMethodMember) {
                            memberValues = staticMethodMember.Invoke(null,new object [0]) as IEnumerable;
                        }
                        else if (null != instanceMethodMember) {
                            var instance = Activator.CreateInstance(fixture);
                            memberValues = instanceMethodMember.Invoke(instance, new object[0]) as IEnumerable;
                        }
                        else if (null != staticPropMember) {
                            memberValues = staticPropMember.GetValue(null) as IEnumerable;
                        }
                        else if (null != instancePropMember) {
                            var instance = Activator.CreateInstance(fixture);
                            memberValues = instancePropMember.GetValue(instance) as IEnumerable;
                        }
                        else {
                            Console.WriteLine("*** Ooops...Looks like I don't know how to get {0} for fixture {1}", sourceName, fixture.ToString());
                            continue;
                        }

                        foreach (var memberValue in memberValues) {
                            if (null != memberValue as IEnumerable) {
                                PrintTestName(fixture.ToString(), method.Name + ExtractArguments(memberValue as IEnumerable));
                            }
                            else {
                                PrintTestName(fixture.ToString(), method.Name + "(" + memberValue.ToString() + ")");
                            }
                        }
                    } else {
                        Console.WriteLine("*** Ooops...Looks like I don't know how to handle test {0} for fixture {1}", method.Name, fixture.ToString());
                    }
                }
            }
            else {
                PrintTestName(fixture.ToString(), method.Name);
            }
        }
    }
}

static string ExtractArguments(IEnumerable arguments) {
    string caseArgs = "(";
    bool first = true;
    foreach (var arg in arguments) {
        if (first) first = false;
        else caseArgs += ",";
        caseArgs += Convert.ToString(arg);
    }
    return caseArgs + ")";
}

static void PrintTestName(string fixture, string testName) {
    Console.WriteLine("{0}.{1}", fixture, testName);
    //Console.WriteLine("nunit-console /run:{0}.{1} {2}", fixture, testName, assemblyName);
}

如果您查看上面的代码,您可能会注意到我已经处理了用于测试的TestCaseSource 是一个命名属性/方法/字段的字符串的功能。您还会注意到虽然有 more 代码,但它仍然是非常简单的代码,因此如果您使用 TestCaseSource 的替代版本,或者如果您有其他 NUnit 属性,它可以很容易地扩展'正在使用我没有满足的需求。

在上面添加一个计数器也很容易,这样您就可以放心地打印与 nunit-console 将运行的测试数量相同的测试数量。

【讨论】:

  • 这将获得基础知识,但如果您使用一些更高级的属性可以从不同的输入自动生成测试,那么您就不走运了!
  • @SebastianGood 我在上面添加了对 TestCase + 一些 TestCaseSource 排列的支持。如果您使用替代选项,扩展代码以处理其他 TestCaseSource 选项(或我尚未找到的其他属性)应该很简单,但是我将把它作为读者练习。跨度>
  • 您还需要考虑测试类从具有这些属性的(抽象)基类继承的情况。然后需要调整计数以多次运行相同的测试方法,
【解决方案2】:

现在有--explore 命令行选项,可用于在不运行测试的情况下列出所有测试用例。更具体的

nunit3-console.exe MyProject.dll --explore

欲了解更多信息:https://github.com/nunit/docs/wiki/Console-Command-Line#description

【讨论】:

    猜你喜欢
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多