Get 'test method' name in a property which is called by TestCaseSource

1,401 views
Skip to first unread message

tk

unread,
Feb 26, 2012, 5:46:26 AM2/26/12
to NUnit-Discuss
Hi

I am trying to data drive by test using excel sheet. My requirement is
that based on the name of the test i need to pull appropriate data for
the test.

In the code below inside TestCaseDataList i need to find out what is
the name of the test. Usually I use TestContext to get the test method
but this runs before the test is even run so can't use that.

[TestFixture]
class TestSuite
{
[Test]
[TestCaseSource(typeof(MyFactoryClass), "TestCaseDataList")]
public void MyTestMethod(string apikey, string userid,
string productid)
{
Console.WriteLine(apikey);
Console.WriteLine(userid);

Console.WriteLine(productid);
}
}

public class MyFactoryClass
{
public static IEnumerable<TestCaseData> TestCaseDataList
{
get
{
string mydata="";
mydata= GetTestMethodName().Tostring //Something
like this i need
List<TestCaseData> testCaseDataList =
ExcelDataManager.GetExcelData(mydata);

foreach (TestCaseData testCaseData in
testCaseDataList)
{
yield return testCaseData;
}
}
}
}
}

Please help as soon as possible.

Charlie Poole

unread,
Feb 26, 2012, 11:12:35 AM2/26/12
to nunit-...@googlegroups.com
Sorry, there's really no way to do that right now, for exactly the
reason you stated: no test is running at the point when the data
is generated.

The workaround would be to have datasources within each
test class specific to the request and let them pass the
required key to a central routine that manages the spreadsheet.

I suggest you add a feature request for parameterized test case
sources at http://bugs.launchpad.net/nunit-3.0

Charlie

> --
> You received this message because you are subscribed to the Google Groups "NUnit-Discuss" group.
> To post to this group, send email to nunit-...@googlegroups.com.
> To unsubscribe from this group, send email to nunit-discus...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/nunit-discuss?hl=en.
>

Naresh

unread,
May 15, 2012, 10:14:56 AM5/15/12
to nunit-...@googlegroups.com
Hello,

I am also facing the similar problem.

Could you please share your solution if it got reolved.

Thanks,
Naresh

tk

unread,
Jul 11, 2012, 9:15:16 PM7/11/12
to nunit-...@googlegroups.com
Hi Charlie

i had asked this enhancement some time not sure you had time to look at this feature request. It would be nice if  you could triage it or if possible to include this in the any of the upcoming releases. 


Thanks
TK

Charlie Poole

unread,
Jul 11, 2012, 10:44:28 PM7/11/12
to nunit-...@googlegroups.com
It has always been my plan to have some sort of dynamic testcase
capability in 3.0... I'm just not 100% sure what it will look like. I
did triage the bug so that it's clear and gave it a new tag
'dynamic_testcase', which I'll use to collect other requests
pertaining to test case data, which is not available until the point
when the test is run.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/nunit-discuss/-/2JrALygRlpoJ.

David Laidlaw

unread,
Jan 20, 2014, 4:37:47 PM1/20/14
to nunit-...@googlegroups.com
I'm in the same boat where I need the method name, it doesn't even have to be at time when your are enumerating the data.

Basically I am trying to keep a naming convention which makes sense - classname.methodname (Test) and then if a from TestCaseSource I would add my own name descriptor.
non datadriven test:
 - MyTests.Test
data driven test:
 - MyTests.Test.test1
 - MyTests.Test.test2
 - etc

What I am stuck doing is setting the description of the test using SetDescription and allowing nunit to set the method name (it does this when blank). Later when I am looping thru all of my methods I rip the method name used back out and do my own string rejigging to make it work in this format... very hackish!
If you watch when you provide your own test name - it totally loses the calling method name in the TestName field (it looks like it goes classname.classname). Why it does this when the default name for TestName you get if you do not set it is left including method is annoying.

If possible - have a getter method - assign it when you know the method name after the test is running. At least at that point I can figure it out and use that to build up proper test names.

Charlie Poole

unread,
Jan 20, 2014, 10:21:57 PM1/20/14
to nunit-...@googlegroups.com
Hi David,

I may have been a bit imprecise in my earlier response, so let's get
more exact now!

Method name is always the same, at least until you change your code.
Ditto class name.

NUnit's "Test name" is completely arbitrary. We could have used a
random string of some kind. It doesn't even have to be unique.

I responded to the earlier post that we could not provide the "test
name" at the time of constructing the test cases. That remains true.
At that point, we don't have a test name - or even a candidate test
name - because we don't yet have the arguments, which form part of our
standard naming. Of course, we do have and could somehow provide the
class and method name. Probably the easiest way is would be to make
the MethodInfo for the test available to data source. Another approach
would be to allow you to put a special macro in your own name, for
which we would substitute the method name. This second approach would
not allow you to provide different data to different methods through
the same source.

So, if we think that being able to provide different data to different
methods is a GoodThing, then we should use the first approach. If it's
a BadThing, then we should use the second. Personally, I'm very
suspicious of allowing code that is part of the tests - as the
TestCaseDataSource is - to know so much about the tests that are
running. It seems like a bad design. What do you think?

Charlie
> To unsubscribe from this group and stop receiving emails from it, send an
> email to nunit-discus...@googlegroups.com.
>
> To post to this group, send email to nunit-...@googlegroups.com.
> Visit this group at http://groups.google.com/group/nunit-discuss.
> For more options, visit https://groups.google.com/groups/opt_out.

Zechtitus

unread,
Jan 29, 2014, 1:27:43 AM1/29/14
to nunit-...@googlegroups.com, nunit-...@googlegroups.com
What I ended up doing was to create a property to store the desired name of data driven test (unique, whateve was needed to represent a fully qualified pathto that test). I then let nunit set the name (I did not set it in the IEnumerable), parsed out the MethodName and then added my descriptor for the test and used that.

The main reason I was wanting to keep the Method name was for readability... I am storing the results of the test runs to a database and wanted the test names to resemble the test including the method name.

If you exposed the MethodInfo - that is probably what I need... At least a person can fully qualify the name of thier test without the workaround of using properties and such.

I will see about making a mock up method using the Ienumerable and a getter for the test name using the workaround - may help someone else trying something similar. i'll see what I can whip up tomorrow.

Sent from my iPhone
> You received this message because you are subscribed to a topic in the Google Groups "NUnit-Discuss" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/topic/nunit-discuss/3tPvHJi9QXI/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to nunit-discus...@googlegroups.com.

David Laidlaw

unread,
Jan 30, 2014, 12:29:56 PM1/30/14
to nunit-...@googlegroups.com
Here is a quick example on how I use this (sort of - had to trim out any business logic). Basically I show the difference between obtaining a name thru TextContext.CurrentContext.Test.FullName and where it is missing the Method Name, and my hack using a property in the enum to set a name and adding it back in thru what is given when you do not override the SetName. Exposing the MethodInfo would be handy as then a user could garner this information after the fact and avoid this workaround.




using System;
using System.Collections;
using System.Linq;
using NUnit.Framework;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }

    public class ParentTestClass
    {
        /// <summary>
        /// NOTE - In order to properly separate testnames, datadriven tests using TestCaseSource must have the Property DATADRIVEN added to it
        /// currently nunit provides no other way to get at the method aside from using the description field for the method name and letting nunit return
        /// methodName (when nothing is provided).
        /// - Do NOT set TestName in IEnumerable
        /// - Do SetProperty("DATADRIVEN", propertyValue);
        /// </summary>
        protected static string TestName
        {
            get
            {
                var type = typeof (ParentTestClass);
                var dic = TestContext.CurrentContext.Test.Properties;

                var datadriven = (from DictionaryEntry t in dic where t.Key.ToString() == "DATADRIVEN" select t.Value.ToString()).FirstOrDefault();
               
                var s = type.Namespace;
                if (s == null)
                    throw new Exception("TestName: unable to determine namespace");

                var newName = TestContext.CurrentContext.Test.FullName.ToLowerInvariant().Split('(')[0];
                if (!string.IsNullOrEmpty(datadriven)) // we are dealing with a datadriven test to parse name out
                    newName = newName + "." + datadriven.ToLowerInvariant();

                return newName;
            }
        }
    }
   
    [TestFixture]
    public class TestClass : ParentTestClass
    {
        [Test, TestCaseSource(typeof(TestClass), "DataWithNameSet")]
        public void TestDataWithNameSet(int x, int y)
        {
            try
            {
                // Will give ConsoleApplication1.TestClass.TestDataWithNameSet(0,0)
                var tName1 = TestContext.CurrentContext.Test.FullName;

                //consoleapplication1.testclass.testdatawithnameset.test_x0_y0
                var tName2 = TestName;
            }
            catch (Exception e)
            {
            }
        }

        public static IEnumerable DataWithNameSet
        {
            get
            {
                for (var x = 0; x < 10; x++)
                {
                    for (var y = 0; y < 10; y++)
                    {
                        var test = new TestCaseData(x, y);
                        test.SetProperty("DATADRIVEN", string.Format("Test_x{0}_y{1}", x, y));
                        yield return test;
                    }
                }
            }
        }
    }
}

Charlie Poole

unread,
Jan 30, 2014, 5:07:12 PM1/30/14
to nunit-...@googlegroups.com
That's definitely another option. The MethodInfo allows you to get the
name and full name of the method as well as the Type for the fixture
class.

Charlie

Visar Elmazi

unread,
Jul 16, 2015, 10:22:37 AM7/16/15
to nunit-...@googlegroups.com
Everyone, there's a new [CallerMemberName] attribute in .NET 4.5. Which, if configured in attribute's constructor will give you exactly that.
See, I extended TestCaseSource into TestCaseSourceEx and put an additional argument called methodName with the [CallerMemberName],
and leave this argument empty when setting the attribute, and you're done.
Now, you get to have the method name where the attribute was applied.
But don't wish for more, no declaring type, etc. Just the method name, and I think the class file name is available too.

The sample code works fine.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class TestCaseSourceEx : TestCaseSourceAttribute
{
    public TestCaseSourceEx(Type sourceType, string sourceName, [CallerMemberName] string methodName = null)
        : base(sourceType, sourceName)
    {

    }
    public TestCaseSourceEx(string sourceName, [CallerMemberName] string methodName = null)
        : base(sourceName)
    {
     
    }
}

[TestFixture]
public class SampleTests
{
    public IEnumerable List = new[] { new string[] { "test-username", "test-password" } };

    [Test, TestCaseSourceEx("List")]
    public void SampleTests_LoginTest(string username, string password)
    {

    }
}

Charlie Poole

unread,
Jul 16, 2015, 10:37:03 AM7/16/15
to NUnit-Discuss
Nice idea! I'll try applying this to the 4.5 build for TestCaseSource,
ValueSource and the new TestFixtureSource attributes and see how it
works.

This is actually a compiler feature, starting with C# 5. I don't think
we currently build using anything earlier than C# 5, so that is
probably not a problem but I'll have to check into mono support.

Since it is a compiler feature, It may be possible to make it work in
.NET 4.0 and earlier by conditionally defining the atttribute
ourselves.

Charlie
> --
> You received this message because you are subscribed to the Google Groups
> "NUnit-Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to nunit-discus...@googlegroups.com.
> To post to this group, send email to nunit-...@googlegroups.com.
> Visit this group at http://groups.google.com/group/nunit-discuss.
> For more options, visit https://groups.google.com/d/optout.

Charlie Poole

unread,
Jul 16, 2015, 10:53:25 AM7/16/15
to NUnit-Discuss
Oh, never mind, you're solving a different problem from what I
thought! Embarassing. :-)

I was thinking we could use this to get the name of the TestCaseSource
method, property or field. But of course the attribute is applied to
the test method not to the actual source member. Best approach remains
the use of the nameof operator in C# 6.

Michael

unread,
Jul 17, 2015, 4:30:02 AM7/17/15
to nunit-...@googlegroups.com
Indeed I was going to suggest the coming C# 6 nameof operator. That's like typeof yielding a compile time constant string.

Charlie Poole

unread,
Jul 17, 2015, 10:27:09 AM7/17/15
to NUnit-Discuss
In fact, it was the availability of nameof that convinced me _not_ to
deprecate the constructors containing names as strings.

On Fri, Jul 17, 2015 at 1:30 AM, Michael <mwpow...@gmail.com> wrote:
> Indeed I was going to suggest the coming C# 6 nameof operator. That's like typeof yielding a compile time constant string.
>

Ganesh Sawant

unread,
Aug 19, 2016, 8:25:23 AM8/19/16
to NUnit-Discuss
Hi Charlie,
Please let us know if this enhancement has been checked in and available to use.
Thanks,
Ganesh.

Charlie Poole

unread,
Aug 19, 2016, 2:02:08 PM8/19/16
to NUnit-Discuss
Hi Ganesh,

No further work has been done on this due to time constraints.

Looking back through the issues, I can see it's not clear which one or
ones are related to this feature. I'm going to designate issue #3 in
the nunit repository as the key issue for implementing dynamic test
cases. I'll change the description and make it into an Epic that
includes all the other issues that depend on having the ability to
create test data each time the tests execute rather than only once
when they load.

You'll be able to follow progress by watching issue #3 and any of it's
dependent issues.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to nunit-discus...@googlegroups.com.
> To post to this group, send email to nunit-...@googlegroups.com.
> Visit this group at https://groups.google.com/group/nunit-discuss.

Charlie Poole

unread,
Aug 19, 2016, 2:05:01 PM8/19/16
to NUnit-Discuss
Hi Ganesh,

Correction to my last post... that key issue will be #7, not #3.

Charlie

Ganesh Sawant

unread,
Aug 22, 2016, 5:26:27 AM8/22/16
to NUnit-Discuss
Hi Charlie,
Thanks for the prompt reply.
Till the time issue got fixed can you please suggest me any alternative to my problem.

We have created a custom Automation test framework to read multiple excel files from a path. These test file have all testcase data. Now If I use TestCaseSource that I can read all files but not able to separate the test flow per excel file. Furthermore we find that the parallel testing is not possible in such approach.
So we are trying to use TestFixtureSource and TestCaseSource attributes together to construct the test flow and execution in nUnit. We need a separate fixture per excel file. So we need to pass the test fixture parameters to TestCaseSource property to access that specific file to construct required test flow.

Thank You,
Ganesh.

Charlie Poole

unread,
Aug 22, 2016, 1:39:08 PM8/22/16
to NUnit-Discuss
Hi Ganesh,

If you use TestFixtureSource, then each instance of your test fixture
will get a different set of constructor arguments. You can then tailor
each instance to be specialized for a particular browser. Options you
have for tailoring each instance:
1. Do it in the constructor
2. Save values in the constructor and do it in the OneTimeSetUp
3. Save values in the constructor and do it in each individual test setup.
4. Save values in the constructor and do it in each individual test method.

It seems to me this should meet your needs, but if I haven't fully
understood the problem, please ask again!

Charlie

Ganesh Sawant

unread,
Aug 22, 2016, 2:58:36 PM8/22/16
to NUnit-Discuss
Thanks again Charlie for the prompt reply. I will give it a try and let you know the outcome... Thanks again for investing your valuable time. This means a lot to me.

Ganesh Sawant

unread,
Aug 23, 2016, 1:37:04 AM8/23/16
to NUnit-Discuss
Hi Charlie,
I am still struggling for passing value to TestCaseSource function while creating test flow in nUnit [Left Side tree structure in nUnit]. nUnit is not calling the OneTimeSetup or constructor function to set initial values for that fixture.
When I am selecting the required Dll through nUnit then nUnit is following below execution pattern. [Note that there are 2 excel files in given path and each excel file has 1 testcase]

1. Call to FixtureParms [First Excel File].
2. Call to FixtureParms [Second Excel File]].
3. Call to TestCases [Here we are not able to pass Excel File Name] . Hence it is reading both the Excel Files from path.
4. Call to TestCases [Here we are not able to pass Excel File Name] . Hence it is reading both the Excel Files from path.


But if I try to Run any TestCase through nUnit then its working fine.

<TestFixture(), TestFixtureSource("FixtureParms")> _
Public Class AllTests
    Public Shared strScriptName As String
   
<OneTimeSetUp> _
    Public Sub fixtureSetup()
        MsgBox("In FixtureSetup")
    End Sub

    Sub New(ByVal str As String)
        MsgBox("In New")
        strScriptName = str
    End Sub

   
<Test(), TestCaseSource("TestCases")> _
    Public Shared Sub start()
        ExecuteTestFlow()
    End Sub

''' Function will fetch data from excel file and will return Enumerable object of all the TestCases
''' Now this function will be called for each fixture separately. But we are not getting any way to pass the fixture parameter to it. So ''' the generateTestCaesfromXLFile is getting null parameter and its reading all the files to construct TestCases.
    Public Shared Property TestCases() As IEnumerable(Of TestCaseData)
        Get
            Return (generateTestCasesfromXLFile(strFileName))
        End Get
    End Property

''' Function will read all excel file names from RunTime folder and will create a seperate fixture for each file.
    Public Shared Property FixtureParms As IEnumerable(Of TestFixtureData)
        Get
            Dim oList As New List(Of TestFixtureData)
            Dim oDirectoryInfo As New DirectoryInfo("c:\seleniumLive\RunTime\")
                For Each ofile As FileInfo In oDirectoryInfo.GetFiles("*.xlsx", SearchOption.TopDirectoryOnly)
                    oList.Add(New TestFixtureData(ofile.FullName))
                Next
            Return oList
        End Get
    End Property
End Class

Below is the nUnit 3 screenshot.

Reply all
Reply to author
Forward
Message has been deleted
Message has been deleted
0 new messages