Java 当测试一个方法时,你能在该方法所引用的单例上模拟变量吗?
我想用JUnit/Mockito测试一个方法 该方法接受一个整数,Java 当测试一个方法时,你能在该方法所引用的单例上模拟变量吗?,java,unit-testing,junit,mockito,Java,Unit Testing,Junit,Mockito,我想用JUnit/Mockito测试一个方法 该方法接受一个整数,用户想要的行数 然后,该方法将该值与另一个值totalNumberOfRowsInDB进行比较,并返回请求的行数(随机选取)。如果用户请求的数量超过可用数量,他们只会得到可用的总数 到目前为止一切都很好 我的问题是,测试这种方法的行为 totalNumberOfRowsInDB是一个保存在单例上的变量。我这样做的原因是因为它将在启动时设置,并且在应用程序执行期间不会更改,并且我希望避免对DB不断的unsecssay调用,以便在它永
用户想要的行数
然后,该方法将该值与另一个值totalNumberOfRowsInDB
进行比较,并返回请求的行数(随机选取)。如果用户请求的数量超过可用数量,他们只会得到可用的总数
到目前为止一切都很好
我的问题是,测试这种方法的行为
totalNumberOfRowsInDB
是一个保存在单例上的变量。我这样做的原因是因为它将在启动时设置,并且在应用程序执行期间不会更改,并且我希望避免对DB不断的unsecssay调用,以便在它永远不会更改的情况下不断计算行数
如果我让我的测试假设总共有10行(这是我在实际基础上拥有的),那么测试是有效的,但是我不希望我的测试依赖于我的清理数据,因为如果我再添加几行,它将破坏测试
问题:我如何修改(模拟)驻留在我实际尝试测试的方法内部的静态变量?我完全愿意接受关于如何改进我的设计的建议/建议,如果它完全错误
这是一个小演示,展示了我的问题的简化版本:
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;
}
}
使用反射,可以修改专用字段:
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
使用反射,可以修改专用字段:
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
我这样做的原因是因为它将在启动时设置,并且在应用程序执行期间不会更改
在这种情况下,我建议为这个属性公开setter,这样您的类肯定更“可测试”。在我看来,为这样的目的编写singleton不是一个好主意
无论如何,为了修改类中用于单元测试的私有字段(例如在生产代码中自动连接),您可以使用例如org.springframework.test.util.ReflectionTestUtils
(或者根据它们的代码编写您自己的反射解决方案)
我这样做的原因是因为它将在启动时设置,并且在应用程序执行期间不会更改
在这种情况下,我建议为这个属性公开setter,这样您的类肯定更“可测试”。在我看来,为这样的目的编写singleton不是一个好主意
无论如何,为了修改类中用于单元测试的私有字段(例如,在生产代码中自动连接),您可以使用例如
org.springframework.test.util.ReflectionTestUtils
(或者根据它们的代码编写您自己的反射解决方案)。您的意思是让测试依赖于“真实”数据吗?i、 表中的实际行数??现在还不清楚您到底想要“模拟”什么,但是如果您想要真实的、非擦洗的数据,我认为您将跳出“纯单元测试”的界限-这取决于您来自哪个阵营-如果要在与“外部世界”没有任何连接的情况下单独测试被测单元,那么您只需“模拟”但是如果你真的希望它基于实际的计数,那么你将处于集成测试的领域(根据pursists的POV),你的意思是让测试依赖于“真实”的数据吗?i、 表中的实际行数??现在还不清楚您到底想要“模拟”什么,但是如果您想要真实的、非擦洗的数据,我认为您将跳出“纯单元测试”的界限-这取决于您来自哪个阵营-如果要在与“外部世界”没有任何连接的情况下单独测试被测单元,那么您只需“模拟”但是如果您确实希望它基于实际计数,那么您将处于集成测试领域(根据pursists的POV)