31

How to get the unit test name from the within unit test?

I have the below method inside a BaseTestFixture Class:

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

My Test Fixture class inherits from the base one:

[TestFixture]
public class WhenRegisteringUser : BaseTestFixture
{
}

and I have the below system test:

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

When I run this from within the Visual Studio, it returns my test method name as expected.

When this runs by TeamCity, instead _InvokeMethodFast() is returned which seems to be a method that TeamCity generates at runtime for its own use.

So how could I get the test method name at runtime?

sharptooth
  • 167,383
  • 100
  • 513
  • 979
The Light
  • 26,341
  • 62
  • 176
  • 258

5 Answers5

26

If you are using NUnit 2.5.7 / 2.6 you can use the TestContext class:

[Test]
public void ShouldRegisterThenVerifyEmailThenSignInSuccessfully()
{
    string testMethodName = TestContext.CurrentContext.Test.Name;
}
nemesv
  • 138,284
  • 16
  • 416
  • 359
23

When using Visual Studio to run your tests if you add a TestContext property in your test class you can get this information easily.

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

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

If you are not using NUnit you can loop over the stack and find the test method:

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";
Michael Lloyd Lee mlk
  • 14,561
  • 3
  • 44
  • 81
  • Do you know if this only works on MSTest? Or it will work on both NUnit and MSTest? – Yoiku Dec 10 '15 at 16:02
  • You would need to change the annotation to be the right annotation for the test framework. However as the accepted answer points out, NUnit has a TestContext which is a better solution. – Michael Lloyd Lee mlk Dec 15 '15 at 17:32
  • Thanks for the answer, I was asking because I am trying to build a FW and I dont want to restrict myself to NUnit or MSTest. So I think what I will do is to loop the stack from the bottom to the top until I find a method which it namespace is not from Microsoft or System. I have tried this and I got good results with MSTest and calling the FW from a command line program (I got the main method). – Yoiku Dec 16 '15 at 18:59
  • please note that in Release builds this sometimes does not work - the test method may be inlined and you will not be able to see the TestAttribute – imaximchuk Oct 04 '17 at 23:18
  • Here's a LINQ one-liner `string testName = new StackTrace().GetFrames()?.Select(stackFrame => stackFrame.GetMethod()).FirstOrDefault(m => m.GetCustomAttributes(typeof(TestAttribute), false).Any())?.Name ?? "Not called from a test method";` – Alain Mar 30 '20 at 15:11
7

Thanks guys; I used a combined approach so it now works in all environments:

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";  
    }
}
sharptooth
  • 167,383
  • 100
  • 513
  • 979
The Light
  • 26,341
  • 62
  • 176
  • 258
  • please note that in Release builds this sometimes does not work - the test method may be inlined and you will not be able to see the TestAttribute – imaximchuk Oct 04 '17 at 23:18
1

If you are not using Nunit or any other third party tool. you will not get TestAttribute.

So you can do this to get Test Method name. Use TestMethodAttribute insted of 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";
    }
Jay Patel
  • 19
  • 5
  • 1
    Here it is as a LINQ one-liner: Here's a LINQ one-liner `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";` – Alain Mar 30 '20 at 15:12