0

I am trying to test some code that uses a static class. The static class has a initialization method which can be called only once and throws exception if called second time. I have multiple test cases which tests the code that need to access the static class. In the code the initialization is done in startup.cs. How do I do something similar for test cases. I am using x-unit for unit testing.

 public static class UniqueId
{
    public static void Initialize()
    {
        if (_generator != null)
            throw new Exception("Already initialized.");
        _generator = new IdGenerator();
    }


    private static IdGenerator _generator = null;
    
    public static BigId NextId()
    {
        if (_generator == null)
            throw new Exception("Not initialized.");
        return _generator.NextId();
    }
}

Code that I want to test:

public string GenerateId
{
    return UniqueId.NextId().ToString()
}
devNull
  • 3,849
  • 1
  • 16
  • 16

3 Answers3

0

In your specific case, you need to set your class to implement the IDisposible and just call Dispose() when you want to destroy it.

Here a example:

namespace Prime.UnitTests.Services
{
    [TestFixture]
    public class YourClassTest
    {

        [SetUp]
        public void SetUp()
        {
            //some configs...
        }

        [Test]
        public void Test_size_String_1()
        {
            UniqueId.Initialize();
            Assert.IsFalse(UniqueId.NextId().ToString() == 10); // quick example...
            UniqueId.Dispose();
        }

        [Test]
        public void Test_size_String_2XPTO()
        {
            UniqueId.Initialize();
            Assert.IsFalse(UniqueId.NextId().ToString() == 115); // quick example...
            UniqueId.Dispose();
        }

    }
}


public static class UniqueId : IDisposable  
{
    public static void Initialize()
    {
        if (_generator != null)
            throw new Exception("Already initialized.");
        _generator = new IdGenerator();
    }


    private static IdGenerator _generator = null;
    
    public static BigId NextId()
    {
        if (_generator == null)
            throw new Exception("Not initialized.");
        return c.NextId();
    }

    public void Dispose()
    {
        _generator?.Dispose(); //Depends of the context of your IdGenerator
        //or
        _generator == null;
    }
}
Jose Cruz
  • 11
  • 3
0

Assuming I understood, in MSTest, look into [TestInitialize], [ClassInitialize] (likely what you need) and see if either works for your use case for a "startup" function

[TestInitialize]

  • runs before all your unit tests (each)

[ClassInitialize]

  • runs once, the only official doc I can find these days is older...

ClassInitializeAttribute Class

Identifies a method that contains code that must be used before any of the tests in the test class have run and to allocate resources to be used by the test class. This class cannot be inherited.

Remarks

When run in a load test, the method marked with this attribute will run once, and any initialization operations it performs will apply to the entire test. If you need to do initialization operations once for every virtual user iteration in the test, use the TestInitializeAttribute.

The order that methods will be run is:

  1. Methods marked with the AssemblyInitializeAttribute.

  2. Methods marked with the ClassInitializeAttribute.

  3. Methods marked with the TestInitializeAttribute.

  4. Methods marked with the TestMethodAttribute.

Only one method in a class may be decorated with this attribute.

Important

This attribute should not be used on ASP.NET unit tests, that is, any test with [HostType("ASP.NET")] attribute. Because of the stateless nature of IIS and ASP.NET, a method decorated with this attribute may be called more than once per test run.

Hth

EdSF
  • 11,753
  • 6
  • 42
  • 83
-2

It depends on which test framework you're using.

EDIT: I see now that you're using xUnit, but I'll leave the entire answer in case it's helpful to someone else.

xUnit

You can check this answer, which talks about how to create a global setup/teardown for a set of tests. To sum up that answer, if you create a constructor for your unit test class in Xunit, that method will be called before each test method. It also states:

A more optimized version would use the IClassFixture interface to ensure that the global initialization/teardown functionality is only called once. For this version, you don't extends a base class from your test class but implement the IClassFixture interface where T refers to your fixture class:

using Xunit;

public class TestsFixture : IDisposable {
    public TestsFixture ()
    {
        // Do "global" initialization here; Only called once.
    }

    public void Dispose()
    {
        // Do "global" teardown here; Only called once.
    } }

public class DummyTests : IClassFixture<TestsFixture> {
    public DummyTests(TestsFixture data)
    {
    }
} 

This will result in the constructor of TestsFixture only being run once for every class under test. It thus depends on what you want exactly to choose between the two methods.

If you're using NUnit it already has a OneTimeSetUp attribute you can use (docs here), like this:

[TestFixture]
public class MyTestFixture
{
    [OneTimeSetUp]
    public void OneTimeSetUp()
    {
        // Initialize things here; only called once
    }
}

If you're using something other than xUnit and NUnit, check the documentation for the framework you use, and look for a one-time setup.

Matt U
  • 4,970
  • 9
  • 28