44

We need some global one time setup code in our test suite. We can do it more than once but it takes quite some time.

  • It's required by all fixtures so [TestFixtureSetUp] does not work. It has to run before all [TestFixtureSetUp] code.

  • Put it in Main() since we keep test assemblies as executables. However Main doesn't get executed under GUI client.

  • Creating a separate class with a static constructor for initialization only works when you reference the class which we do not favor doing in each and every class.

  • Inheriting all test fixtures from a base class and adding a static constructor to it causes multiple calls to the init code.

Now given the circumstances, I have two questions:

1) Is "global setup" a very bad idea that it's not supported by NUnit?

2) What's the least painful, most common way to achieve this?

Sedat Kapanoglu
  • 46,641
  • 25
  • 114
  • 148
  • 1
    By the way for those who wonder, MBUnit supports "AssemblyFixture" classes whose fixture setup code is run once per assembly. I know my question was about NUnit but anyone who's thinking about a switch should consider that as well. – Sedat Kapanoglu Apr 27 '11 at 06:33

5 Answers5

90

[SetUpFixture]

This is the attribute that marks a class that contains the one-time setup or teardown methods for all the test fixtures under a given namespace.

The SetUp method in a SetUpFixture is executed once before any of the fixtures contained in its namespace. The TearDown method is executed once after all the fixtures have completed execution.

Assembly wide initialization. If you don't put the class in any namespace, it will apply to all tests in the assembly.

eg.

// using statements

[SetUpFixture]
public class GlobalSetup {
  [SetUp]
  public void ShowSomeTrace() {
    Trace.WriteLine("It works..."); // won't actually trace
  }
}

http://www.nunit.org/index.php?p=setupFixture&r=2.4

ajukraine
  • 561
  • 9
  • 27
6opuc
  • 1,176
  • 3
  • 13
  • 21
  • Oh I thought `SetUpFixture` and `TestFixtureSetUp` were the same thing, one being deprecated. That's the answer, thanks! – Sedat Kapanoglu Apr 29 '11 at 11:15
  • 12
    It says this in the docs, but to point it out explicitly..... If you don't put this class into a namespace at all, it will be used for "assembly wide" setup/teardown. – Greg Biles Oct 04 '11 at 14:43
  • @GregB I've added your comment into the actual answer, cheers. – ashes999 Jan 24 '13 at 20:30
  • @GregB Thanks so much! Your small comment was more helpful than the few dozens threads/articles I read to solve my problem :) – Shautieh Dec 06 '13 at 16:22
  • Although it should't be overused it is useful for setting up eg. a logging framework – JacobE Oct 31 '15 at 10:42
  • How to pass data from GlobalSetup to classes with tests? Make GlobalSetup singleton? – Denis535 Mar 19 '17 at 20:16
  • 4
    As of nUnit 3, the [SetUp] attribute is not used in the SetUpFixture and the above code will throw an exception. Instead use [OneTimeSetUp] and [OneTimeTearDown]. https://github.com/nunit/docs/wiki/SetUpFixture-Attribute – dylanT Oct 12 '17 at 22:39
18

Starting from NUnit 3.0, the Setup attribute is no longer supported inside classes marked with the SetUpFixture attribute. The current valid syntax is:

  [SetUpFixture]
  public class MySetUpClass
  {
    [OneTimeSetUp]
    public void RunBeforeAnyTests()
    {
      // ...
    }

    [OneTimeTearDown]
    public void RunAfterAnyTests()
    {
      // ...
    }
  }

The OneTimeSetUp method in a SetUpFixture is executed once before any of the fixtures contained in its namespace. The OneTimeTearDown method is executed once after all the fixtures have completed execution.

Current SetUpFixture documentation page

Leaky
  • 3,088
  • 2
  • 26
  • 35
11

As stated in my comment, you can achieve assembly wide init by using a SetUpFixture located on the assembly level. I needed this to turn off the UI on the default trace listener:

[SetUpFixture]
public class AssemblySetup
{
    [SetUp]
    public void Setup()
    {
        var traceListener = Debug.Listeners.Cast<TraceListener>().FirstOrDefault(listener => listener is DefaultTraceListener) as DefaultTraceListener;

        if (traceListener != null)
            traceListener.AssertUiEnabled = false;
    }
}

More about assembly or namespace setup: http://www.nunit.org/index.php?p=setupFixture&r=2.4

Note: As pointed out by others, don't use this to corrupt isolation between your tests.

Marius
  • 9,208
  • 8
  • 50
  • 73
1

I don't think there is a nice, built in way to achieve it unfortunately - probably because NUnit is meant to be used for unit tests mainly, and you shouldn't need any global setup for unit tests (everything should be locally mocked in every test fixture).

It is however quite common to use NUnit for integration tests, and there it is very common to have a global setup - as in your case. There are a few reasonable options here:

  1. On my current project we usually do in in the msbuild script that is running the tests. The benefits are that you don't need to remember about any special setup when you write new tests. The downside - you have to make sure you have everything set up when you run the tests from IDE.

  2. If the above is not an option you can use your last idea - to inherit the tests from a common base class. The base class could then reference a singleton class (you can find i.e. Jon Skeets article on how to implement a singleton), which would do the setup. This way it will be run only once.

Grzenio
  • 35,875
  • 47
  • 158
  • 240
  • I want to set "AssertUIEnabled" to false on the default trace listener so that I don't get a popup if an assertion fails somewhere in the code stack. This is something I want to do once and I want it to happen for all tests. – Marius Feb 09 '11 at 08:03
  • 1
    I'm testing an MVC3 app that uses ActiveRecord, which I need to initialize, once, before running all tests -- how's that for a good use case? :) – ashes999 Nov 14 '11 at 19:30
0

1) I guess it depends on the context. I've never needed a global setup on any project, but I can imagine scenarios, e.g. an app that only reads data, and a common, global data setup.

2) You could make your global setup, e.g. in the fixture base you mention, stateful. I.e. have a HasRun property or the like that is checked before execution.

Martin R-L
  • 4,039
  • 3
  • 28
  • 28