开发者

When testing a method, can you mock variables on singletons which that method refers to?

I've got a method that I'd like to test with JUnit/Mockito.

The method takes in one Integer, numberOfRowsThatTheUserWants.

The method then compares that value, against another value totalNumberO开发者_如何学运维fRowsInDB and will return the requested number of rows(randomly picked). If the user requests more than is available, they'll just get the total that are available.

All is fine up to this point.

The problem I have, is testing this methods behaviour.

totalNumberOfRowsInDB is a variable held on a singleton. My reason for doing this was because it would be set at startup and would not change during the execution of the application, and I wanted to avoid constant unneccssay calls to the DB to constantly count the rows when it would never change.

Testing works if I make my tests assume there is a total of 10 rows (as that is what I have on the actual base), however I don't want my tests to be dependent on my scrub data, because if I add a few more rows, it'll break the tests.

Question : How can I modify(mock) a static variable that resides INSIDE of the method I'm actually trying to test? I'm completely open to suggestions / advice on how to improve my design if its awfully wrong...

This is a little demo to show a simplified version of my issue:

public class MockMe
{
    public static void main(String[] args)
    {
        // Setting to 5, but this comes from user input
        Integer numberOfRowsThatTheUserWants = 5;
        MockMe myMockMe = new MockMe();
        myMockMe.myMethod(numberOfRowsThatTheUserWants);
    }

    private void myMethod(Integer numberOfRowsThatTheUserWants)
    {
        if(numberOfRowsThatTheUserWants > MySingleton.getInstance().getTotalRowsOnDB())
        {
            System.out.println("You've requested more than is available, so I'll just give you all I've got instead");
        }
        else
        {
            System.out.println("Here are your " + numberOfRowsThatTheUserWants + " rows as requested, sir!");
        }
    }
}

class MySingleton
{
    private static MySingleton mySingleton;
    private int totalRowsOnDB;

    private MySingleton()
    {
        //private constructor to prevent instantiation
    }

    public int getTotalRowsOnDB()
    {
        return totalRowsOnDB;
    }

    public static MySingleton getInstance()
    {
        if (mySingleton == null)
        {
            mySingleton = new MySingleton();
            // this is actually set by SELECT COUNT(*) FROM TABLENAME but setting to 10 for purposes of demo
            //DBManager dbManager = new DBManagerImpl();
            //mySingleton.totalRowsOnDB = dbManager.getTotalRows();
            mySingleton.totalRowsOnDB = 10;
        }
        return mySingleton;
    }
}


My reason for doing this was because it would be set at startup and would not change during the execution of the application

In such case, I'd recommend to expose setter for this property, then your class would be definitely more "testable". Writing singleton for such purpose is not very good idea in my opinion.

Anyway, for modifying private fields in class for unit tests (for example autowired in the production code) you can use for example org.springframework.test.util.ReflectionTestUtils (or write your own reflection solution based on their code).


Using reflection, you can modify a private field:

Field field = MySingleton.class.getDeclaredField("totalRowsOnDB");
field.setAccessible(true); // "Cheat" by setting it to "not private"
field.set(MySingleton.class, 5); // Set it to whatever you like
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜