2

I have some test-code that is initializing some members which should be done just once at the beginning. This is why I used the constructor for that:

[TestFixture]
public class MyTestClass
{
    private readonly IUnitTestGeometryProvider m_GeometryProvider;


    public MyTestClass()
    {
        // do some heavy init-op
    }

    private IEnumerable<TestCaseData> TestCases()
    {
        yield return new TestCaseData(this.m_GeometryProvider.GetPolyline())
            .Throws(typeof(ArgumentException));
    }

    [TestCaseSource("TestCases")]
    public double Check_GetReducedArea_For_Invalid_Arguments(IGeometry theGeom)
    {
        return theGeom.GetReducedArea();
    }
}

I know of the convention to use the FixtureSetup-attribute for initializing tests, e.g. from this question on SO. However I noticed that the method TestCases is executed before the method marked with that attribute so I run into an NullReferenceException when evaluating the different testcases as the m_GeometryProvider is null at this time.

So I debugged my code and set a breakpoint into the constructor. I noticed, that it is executed twice before any test has even been run. I assumed every testcase having its own instance of the MyTestClass, but as I have three different testcases and the constructor running twice this doesn't explain it.

As the initialization is heavy I´d like to execute it just once. Is there a way to guarantee this? I´d like to avoid a static member as it often attracts colleagues to heavily use other static members just because there already is one. Furthermore I´d consider the test-init to be specific for one instance of my MyTestClass instead of the class itself - assuming there´s just one however.

I'm using NUnit 2.5.10.

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • Don't use the constructor for initialization. Use the `TestFixtureSetup` attribute for heavy initialization, not the constructor. Per test initialization methods are marked with the `SetUp` attribute. BTW 2.5.10 is very old. The current version is 3.7 – Panagiotis Kanavos Jun 02 '17 at 08:19
  • @PanagiotisKanavos I already explained why this doesn´t work for me. The problem is that using that attribute the method marked with it run far *after* tha `TestCases`-method which causes the latter to run into an NRE. – MakePeaceGreatAgain Jun 02 '17 at 08:21
  • 1
    @PanagiotisKanavos it will throw error since TestCases run before Setup – Ray Krungkaew Jun 02 '17 at 08:21
  • Ironically, as much as you try to avoid static method, TestCases method is required to be static in Nunit3 :D – Ray Krungkaew Jun 02 '17 at 08:22
  • @HimBromBeere TestCase is an attribute, not a method. A *TestCaseSource* is different. It's not a good idea to mix names like this. – Panagiotis Kanavos Jun 02 '17 at 08:25
  • @PanagiotisKanavos I talked about `TestCases` (be aware of the plural), which *is* a method in my case. – MakePeaceGreatAgain Jun 02 '17 at 08:27

1 Answers1

4

Basically NUnit reserves the right to construct your fixture object whenever it needs to, as often as it needs to. Therefore, you should avoid doing heavy initialization in your constructor, especially if some initialization is only needed when the tests are being run.

Generally, initialization for executing the tests should be done in the TestFixtureSetUp method, which is run once and only once each time the fixture is executed. This is more complicated, however, when you are generating test cases using a TestCaseSource attribute.

Because TestCases must be executed in order to create your tests in the first place, eons before they are ever run, an instance of the object must be created to do that. Then when the tests are run, another instance is created for the purpose of running them. There's not enough info in your question to figure out why there are two "extra" calls to your constructor, but it's either due to some other aspect of your code or simply a bug in the somewhat old version of NUnit you are using. You would have to step through those constructor calls and examine the stack trace to see what is calling them.

Is your m_GeometryProvider member used anywhere else besides the TestCases method? If not, you can simplify things by making it a temporary field created in that method. You can then eliminate an extra constructor call by making the TestCases method static. You said you didn't like that, but it's what we recommend. In fact, in NUnit 3.0 and later it is required to be static.

If you have other initialization that's needed to run tests besides the creation of the geometry provider, that should go in a TestFixtureSetUp method.

Charlie
  • 12,928
  • 1
  • 27
  • 31
  • Currently the geometryProvider is just used in that method, but as more tests are implemented I need access to it from those methods also. However thanks a lot for that answer, it clearified some things I already assumed - in particular the fact that on 3.x methods needs to be static. – MakePeaceGreatAgain Jun 02 '17 at 08:19
  • I tried to debug it, but for both calls I get the same stacktrace mentioning just one single method (`JetBrains.ReSharper.UnitTestRunner.nUnit26.dll!JetBrains.ReSharper.UnitTestRunner.nUnit26.DelegatingTestRunner.RunTests(...)`). I added a second method marked with the `TestCaseSourceAttribute` named `OtherTestCases` which yields to the constructor being called **three** times. So obviously the engine calls the constructor once for every `TestCaseSource` as well. – MakePeaceGreatAgain Jun 02 '17 at 08:31
  • Ah... you hadn't mentioned Resharper before. Hopefully, it makes no difference. Yes, your constructor will be called for __each use of__ a non-static TestCaseSource contained in the method. Some versions of NUnit try to cache a single instance, but it's all so long ago that I can't remember which. :-) – Charlie Jun 03 '17 at 00:47
  • Is creation of the GeometryProvider itself expensive? If not, just do it multiple times. – Charlie Jun 03 '17 at 00:51