【问题标题】:How to get the unit test method name at runtime from within the unit test?如何在运行时从单元测试中获取单元测试方法名称?
【发布时间】:2012-03-28 19:44:34
【问题描述】:

如何从单元测试内部获取单元测试名称?

我在 BaseTestFixture 类中有以下方法:

public string GetCallerMethodName()
{
    var stackTrace = new StackTrace();
    StackFrame stackFrame = stackTrace.GetFrame(1);
    MethodBase methodBase = stackFrame.GetMethod();
    return methodBase.Name;
}

我的测试夹具类继承自基类:

[TestFixture]
public class WhenRegisteringUser : BaseTestFixture
{
}

我有以下系统测试:

[Test]
public void ShouldRegisterThenVerifyEmailThenSignInSuccessfully_WithValidUsersAndSites()
{
    string testMethodName = this.GetCallerMethodName();
    //
}

当我在 Visual Studio 中运行它时,它会按预期返回我的测试方法名称。

当它由 TeamCity 运行时,会返回 _InvokeMethodFast(),这似乎是 TeamCity 在运行时生成的供自己使用的方法。

那么如何在运行时获取测试方法名称?

【问题讨论】:

  • 即使是从 VS 启动,它是否在发布模式下编译?
  • 您是否获得堆栈中调用的每个方法的程序集信息?也许你可以在堆栈中寻找你的测试程序集。
  • 堆栈跟踪会有所帮助,以查看实际方法名称是否列在调用堆栈的更远位置。
  • 您有 60 多个问题没有被接受。对帮助你的人感到尊重吗?

标签: c# unit-testing automated-tests teamcity


【解决方案1】:

如果您使用的是NUnit 2.5.7 / 2.6,您可以使用TestContext class

[Test]
public void ShouldRegisterThenVerifyEmailThenSignInSuccessfully()
{
    string testMethodName = TestContext.CurrentContext.Test.Name;
}

【讨论】:

  • MSTest 也在其 TestContext 中公开此信息
  • 它现在可以在 TeamCity 中正常运行,但是当我在 Visual Studio 中本地运行它时,它会引发对象未初始化的异常。那么如何让它在 Visual Studio 中工作呢?
  • @William Wich 你在使用测试运行器吗?
  • 这个答案在 2022 年仍然适用于 NUnit 3.13。
【解决方案2】:

在使用 Visual Studio 运行测试时,如果在测试类中添加 TestContext property,则可以轻松获取此信息。

[TestClass]
public class MyTestClass
{
    public TestContext TestContext { get; set; }

    [TestInitialize]
    public void setup()
    {
        logger.Info(" SETUP " + TestContext.TestName);
        // .... //
    }
}

【讨论】:

    【解决方案3】:

    如果你不使用 NUnit,你可以遍历堆栈并找到测试方法:

    foreach(var stackFrame in stackTrace.GetFrames()) {
      MethodBase methodBase = stackFrame.GetMethod();
      Object[] attributes = methodBase.GetCustomAttributes(typeof(TestAttribute), false);
      if (attributes.Length >= 1) {
        return methodBase.Name;
      } 
    }
    return "Not called from a test method";
    

    【讨论】:

    • 你知道这是否只适用于 MSTest 吗?或者它适用于 NUnit 和 MSTest?
    • 您需要将注释更改为测试框架的正确注释。然而,正如公认的答案所指出的,NUnit 有一个 TestContext ,这是一个更好的解决方案。
    • 感谢您的回答,我之所以这么问,是因为我正在尝试构建 FW,并且我不想将自己限制在 NUnit 或 MSTest 上。所以我认为我要做的是将堆栈从底部循环到顶部,直到我找到一个它的命名空间不是来自 Microsoft 或 System 的方法。我已经尝试过了,使用 MSTest 并从命令行程序调用 FW 得到了很好的结果(我得到了 main 方法)。
    • 请注意,在发布版本中,这有时不起作用 - 测试方法可能是内联的,您将无法看到 TestAttribute
    • 这是一个 LINQ 单行代码 string testName = new StackTrace().GetFrames()?.Select(stackFrame => stackFrame.GetMethod()).FirstOrDefault(m => m.GetCustomAttributes(typeof(TestAttribute), false).Any())?.Name ?? "Not called from a test method";
    【解决方案4】:

    谢谢大家;我使用了一种组合方法,因此它现在适用于所有环境:

    public string GetTestMethodName()
    {
        try
        {
            // for when it runs via TeamCity
            return TestContext.CurrentContext.Test.Name;
        }
        catch
        {
            // for when it runs via Visual Studio locally
            var stackTrace = new StackTrace(); 
            foreach (var stackFrame in stackTrace.GetFrames())
            {
                MethodBase methodBase = stackFrame.GetMethod();
                Object[] attributes = methodBase.GetCustomAttributes(
                                          typeof(TestAttribute), false); 
                if (attributes.Length >= 1)
                {
                    return methodBase.Name;
                }
            }
            return "Not called from a test method";  
        }
    }
    

    【讨论】:

    • 请注意,在发布版本中,这有时不起作用 - 测试方法可能是内联的,您将无法看到 TestAttribute
    【解决方案5】:

    如果您没有使用 Nunit 或任何其他第三方工具。你不会得到 TestAttribute

    所以你可以这样做来获取测试方法名称。 使用 TestMethodAttribute 插入 TestAttribute

        public string GetTestMethodName()
        {
                // for when it runs via Visual Studio locally
                var stackTrace = new StackTrace();
                foreach (var stackFrame in stackTrace.GetFrames())
                {
                    MethodBase methodBase = stackFrame.GetMethod();
                    Object[] attributes = methodBase.GetCustomAttributes(typeof(TestMethodAttribute), false);
                    if (attributes.Length >= 1)
                    {
                        return methodBase.Name;
                    }
                }
                return "Not called from a test method";
        }
    

    【讨论】:

    • 这是一个 LINQ 单行:这是一个 LINQ 单行 public string GetTestMethodName() => new StackTrace().GetFrames()?.Select(stackFrame => stackFrame.GetMethod()).FirstOrDefault(m => m.GetCustomAttributes(typeof(TestMethodAttribute), false).Any())?.Name ?? "Not called from a test method";
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 2021-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-28
    • 1970-01-01
    相关资源
    最近更新 更多