Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test singletons in one test class?

I want to test the behavior of a singleton class with following methods:

public class SomeSingleton
{
    private final static int DEFAULT_VALUE1 = ...;
    private final static int DEFAULT_VALUE2 = ...;

    private static SomeSingleton instance;

    public static void init(int value1, int value2)
    {
        if (instance != null)
        {
            throw new IllegalStateException("SomeSingleton already initialized");
        }

        instance = new SomeSingleton(value1, value2);
    }

    public static getInstance()
    {
        if (instance == null)
        {
            init(DEFAULT_VALUE1, DEFAULT_VALUE2);
        }

        return instance;
    }
}

And then I have a test class with several test methods, which invoke init several times:

@RunWith(PowerMockRunner.class)
@PrepareForTest(SomeSingleton.class)
public class SomeSingletonTest {
    @Test
    public void testGetInstanceSunnyDay()
    {
        [...]
        SomeSingleton.init(...);
        [...]
        SomeSingleton.getInstance();
        [...]
    }

    @Test
    public void testGetInstanceRainyDay()
    {
        [...]
        SomeSingleton.init(...); // IllegalStateException
        [...]
        SomeSingleton.getInstance();
        [...]
    }
}

When I do it this way, I always get the IllegalStateException in the second test because instance != null.

How can I run several tests involving init in one test class?

Putting testGetInstanceSunnyDay and testGetInstanceRainyDay in 2 separate classes solves the problem, but I'm wondering if there is a better solution.

like image 601
Dmitrii Pisarenko Avatar asked Mar 22 '23 08:03

Dmitrii Pisarenko


1 Answers

Fundamentally singletons are hard to test, precisely because of this sort of thing. You could add a clearStateForTesting method:

static void clearStateForTesting() {
    instance = null;
}

... but I'd suggest that you avoid the singleton pattern in the first place, if possible.

Also note that your singleton implementation isn't thread-safe at the moment. There are significantly better implementations if you really need to use a singleton.

like image 145
Jon Skeet Avatar answered Apr 01 '23 04:04

Jon Skeet