Test a Suite of Fixture

Asked by Maxence MODELIN

Hey,
I would like to execute a specific of Fixtures. I can't use the "category" because I determine dynamically fixture to execute.
So I followed the NUnit documentation (on http://www.nunit.org/index.php?p=suite&r=2.5.9), and my program looks to be the same :

public class AllTests
{
        [Suite()]
        private static IEnumerable Suite
        {
            get
            {
                //irectory.GetFiles(ConfigurationPath.GetFolderPath(), "Test-*.psm1");

                var suite = new ArrayList()
                                      {
                                          new FixtureRunner("Test-Install-IrisVente1.psm1"),
                                          new FixtureRunner("Test-Install-IrisVente2.psm1"),
                                          new FixtureRunner("Test-Install-IrisVente3.psm1"),
                                          new FixtureRunner("Test-Install-IrisVente4.psm1")
                                      };

                return suite;
            }
        }
}

 [TestFixture(typeof(string))]
public class FixtureRunner
{
        public FixtureRunner(string name)
        {
            [...]
        }
       [...]

}

When I call the console runner or the nunit Gui (through a command line), the same fixture is executed 4 times instead of executing 4 differents fixtures.

Do you have any idea of how I could use Suite attribute ? Does it still work ?
If not, how can I dynamically decide which fixture to run (a bit like TestCaseSource("FunctionsToTest") but with Fixture).
Thanks for your answer,
max

Question information

Language:
English Edit question
Status:
Solved
For:
NUnit Framework Edit question
Assignee:
No assignee Edit question
Solved by:
Maxence MODELIN
Solved:
Last query:
Last reply:
Revision history for this message
Charlie Poole (charlie.poole) said :
#1

What is your intent in including a parameterized TestFixtureAttribute on
Fixture Runner? It would only be used in a normal run without specifying
a fixture and in that case would cause an error since no argument would
be provided for the constructor.

Assuming you are running the console with /fixture="AllTests", the
four fixtures should be executed. How are you determining that
this is not happening?

Charlie

On Tue, Jan 18, 2011 at 10:54 AM, Maxence MODELIN
<email address hidden> wrote:
> New question #141938 on NUnit Framework:
> https://answers.launchpad.net/nunit-3.0/+question/141938
>
> Hey,
> I would like to execute a specific of Fixtures. I can't use the "category" because I determine dynamically fixture to execute.
> So I followed the NUnit documentation (on http://www.nunit.org/index.php?p=suite&r=2.5.9), and my program looks to be the same  :
>
> public class AllTests
> {
>        [Suite()]
>        private static IEnumerable Suite
>        {
>            get
>            {
>                //irectory.GetFiles(ConfigurationPath.GetFolderPath(), "Test-*.psm1");
>
>                var suite = new ArrayList()
>                                      {
>                                          new FixtureRunner("Test-Install-IrisVente1.psm1"),
>                                          new FixtureRunner("Test-Install-IrisVente2.psm1"),
>                                          new FixtureRunner("Test-Install-IrisVente3.psm1"),
>                                          new FixtureRunner("Test-Install-IrisVente4.psm1")
>                                      };
>
>                return suite;
>            }
>        }
> }
>
>  [TestFixture(typeof(string))]
> public class FixtureRunner
> {
>        public FixtureRunner(string name)
>        {
>            [...]
>        }
>       [...]
>
> }
>
> When I call the console runner or the nunit Gui (through a command line), the same fixture is executed 4 times instead of executing 4 differents fixtures.
>
> Do you have any idea of how I could use Suite attribute ? Does it still work ?
> If not, how can I dynamically decide which fixture to run (a bit like TestCaseSource("FunctionsToTest") but with Fixture).
> Thanks for your answer,
> max
>
> --
> You received this question notification because you are a member of
> NUnit Core Developers, which is an answer contact for NUnit Framework.
>
> _______________________________________________
> Mailing list: https://launchpad.net/~nunit-core
> Post to     : <email address hidden>
> Unsubscribe : https://launchpad.net/~nunit-core
> More help   : https://help.launchpad.net/ListHelp
>

Revision history for this message
Charlie Poole (charlie.poole) said :
#2

How annoying... I posted my comment via email and Launchpad changed the status to Answered.

Revision history for this message
Maxence MODELIN (maxence-modelin) said :
#3

Hey Charlie
Thanks for your first answer.
My goal is to create a wrapper to run fixture written in PowerShell with NUnit.
The FixtureRunner is just a fixture with a parameter. The parameter is the name of the PowerShell script to execute.
The TestSuite has to find all the scripts to run an create a Fixture instance per script.

I know that 4 fixtures are executed because I can count the amount of tests passed. But I also know that it's always the same (the first of the suite) because of their amount. On top of that, the nunit GUI shows 4 tests loaded with always the same parameter (which confirms my idea).

Do you have any idea about how I can solve that and execute a suite of Fixture ?
max

Revision history for this message
Charlie Poole (charlie.poole) said :
#4

What command line do you use in running the tests?

Have you removed the FixtureAttribute to see if it changes any behavior?

You should _either_ use Suite or use a parameterized TestFixture to solve
this problem. Trying to use both at the same time is quite confusing.

Either should work. Use a parameterized fixture with four TestFixture
attributes for a static solution with the tests known in advance. Use
a constructed Suite for a solution that can be built dynamically, based
on the available scripts.

As a third alternative, if each script is but a single test, use a parameterized
test method with script names generated by a data source method.

Charlie

Revision history for this message
Maxence MODELIN (maxence-modelin) said :
#5

Hey Charlie,

I think that I found my solution.
As u suggested me, I removed the FixtureAttribute.
It seems (but maybe I'm wrong), that when a Fixture contained a TestCaseSource, the instantiation is done 2 times.
For reminder, I was trying to make a Suite of Fixtures instantiated with a parameter and each were containing a TestCaseSource based on a property depending of the parameter given.
So finally i deduced :
- the instantiation of the Fixture (done by the Suite) is not the same than the instantiation of the TestCaseSource property : instantiation of a same fixture was done 2 times : once by the Suite and then a second time to generate the TestCaseSource list of tests
Which means that it's not possible to give a parameter to a fixture containing a TestCaseSource because this fixture will be reinstantiated one more time after with the basic constructor (so the parameter will be missing).

I solved my solution with a weird ParameterProvider singleton class containing a queue filled in the Suite creation.
I join my code (maybe that could help someone - i'm not very proud of it but it seems to solve my issue)

Thanks again for your help Charlie and your quick answers!!!
max

public class ParameterProvider
{
 #region Singleton region
 /// <summary>
 /// Private constructor for singleton
 /// </summary>
 private ParameterProvider()
 {
 }
 private static ParameterProvider instance;

 public static ParameterProvider Instance
 {
  get
  {
   if (instance == null)
   {
    instance = new ParameterProvider();
   }
   return instance;
  }
 }
 #endregion

 private Queue<string> _fixturesQueue = new Queue<string>();

 /// <summary>
 /// Provide the first item on the queue, remove it and reinject it at the end of the queue
 /// </summary>
 /// <returns></returns>
 private string Dequeue()
 {
  var item = _fixturesQueue.Dequeue();
  _fixturesQueue.Enqueue(item);
  return item;
 }

 private void Enqueue(string item)
 {
  _fixturesQueue.Enqueue(item);
 }

 /// <summary>
 /// Contains the amount of item contained in the queue
 /// </summary>
 private int Count
 {
  get
  {
   return _fixturesQueue.Count;
  }
 }

 static public void AddOne(string item)
 {
  ParameterProvider.Instance.Enqueue(item);
 }

 static public string GetOne()
 {
  if (ParameterProvider.Instance.Count == 0)
  {
   return null;
  }
  return ParameterProvider.Instance.Dequeue();
 }
}

/// <summary>
/// This property contains the fixture list to execute
/// </summary>
[Suite]
public static IEnumerable Suite
{
 get
 {
  var suite = new ArrayList();
  var files = Directory.GetFiles(ConfigurationPath.GetFolderPath());
  foreach (var file in files)
  {
   FileInfo fileInfo = new FileInfo(file);
   ParameterProvider.AddOne(name);
   suite.Add(new ParametrizedFixture());
  }

  return suite;
 }
}

And the "parametrized" fixture

[TestFixture]
public class ParametrizedFixture
{
 public ParametrizedFixture()
 {
  InitializeFixture();
 }

 private static IList<string> _functionsToTestList;
 private readonly string _testFilePath = ParameterProvider.GetOne();

 #region Properties
 /// <summary>
 /// Provide the function list to test inside this fixture
 /// </summary>
 /// <returns></returns>
 public IEnumerable<string> FunctionsToTest()
 {
  if (_functionsToTestList == null)
  {
   throw new NullReferenceException("Functions list is null");
  }
  return _functionsToTestList;
 }
 #endregion

 private void InitializeFixture()
 {
  // Get function to test in this fixture
  _functionsToTestList = GetFunctions(_testFilePath);
 }

 static private IList<string> GetFunctions(string file)
 {
  // Find the test to execute. For instance :
  var testsToBeDone = new List<string>();
  for (int i=0; i < 3; i++ )
  {
   testsToBeDone.Add("Test" + i);
  }
  // But in my project : this list was depending of the property _testFilePath
  return testsToBeDone;
 }

 [Test]
 [TestCaseSource("FunctionsToTest")]
 public void PowerShell_Tests(string functionToTest)
 {
  // Tests to execute
 }
}