简体   繁体   中英

Testing dates for singleton

I've always tested Dates in such way, that I had a protected method getDate() in my class, which I've overriden for test purposes. Example:

public class MyClass {
    protected Date getDate(){
        return new Date();
    };
}

Test:

MyClass myclass = new MyClass(){
    @Override
    protected Date getDate(){ 
        return new Date(1234567890);
    }
};

That was enough to this day, but the following problem appeared: I have a class that I want to instantiate once, so I use singleton pattern:

public static Something getInstance() {
    if (instance == null) {
        instance = new Something();
    }

    return instance;
}

The problem is that I have to create an object this way: Something.getInstance() - object is created inside that method. I cannot override getDate method inside getInstance, because it wouldnt make sense (sometimes I would need the real instance, sometimes test instance). This leads me to a question: How to test date in such situation?

As you just noticed every time you use plain-old-java singletons, you create untestable code.

There are other ways to have only one instance of a class. From simple - just create it once :) to using IoC frameworks like Spring to let them care about it.

I suggest you to take a look at Misko Hevery's guide to writing testable code , section about global state.

If, and only if the Singleton pattern is not avoidable at any costs, you could mock the construction of the Something class using Powermock :

//create mock instance,     
Something mockSomethingInstance = createMock(Something.class);
//create your Date instance to return
Date d = new Date();
when(mockSomethingInstance.getDate()).thenReturn(d);

You have to mock the constructor of the Something class, to always return the instance you created ( Beware though, doing this will override all other constructions of the Something class too, but in this case, as this is a singleton, it seems OK.):

expectNew(Something.class).andReturn(mockSomethingInstance); 

Also, Powermock can mock static function calls too , so you could mock the getInstance function on the Something class too:

//mock the static functions
mockStatic(Something.class);          

expect(Something.getInstance()).andReturn(mockSomethingInstance);
//have to replay the class in order to work
replay(IdGenerator.class); 

However, I assume you want to do partial mocking , as you want to test the behavior of the class itself. But this is starting to get uglier and uglier...

All in all: think twice before using Singletons - as simple they seem (onlz seem, of course...), in the long run, they can quickly turn into nightmare... Using Spring is a much cleaner way of having the same, saving a lot of headaches.

听起来很多(假设EasyMock是一个选项),你需要使用Capture。

If you put a getDate() method on your singleton then it has what's known as global state , which makes it almost impossible to mock up for testing purposes. Your only alternatives are to use a testing framework, or to change your class not to be a "true" singleton, while ensuring in other ways that only one instance of it can be instantiated. I'd argue that the latter option is the correct approach and you should not be using a singleton in this case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM