Java JMockit-忽略严格期望
我想测试私有方法的行为。 方法“moveDataToArchive”执行4个步骤 它是4x:计算日期+调用子方法 这是我的测试:Java JMockit-忽略严格期望,java,junit,mocking,jmockit,Java,Junit,Mocking,Jmockit,我想测试私有方法的行为。 方法“moveDataToArchive”执行4个步骤 它是4x:计算日期+调用子方法 这是我的测试: @Test public void testMoveData2Archive() throws Exception{ final long now = 123456789000L; //Necessary to make the archivingBean runable. Vector<LogEntry> logCol
@Test
public void testMoveData2Archive() throws Exception{
final long now = 123456789000L;
//Necessary to make the archivingBean runable.
Vector<LogEntry> logCollector = new Vector<LogEntry>();
Deencapsulation.setField(archivingBean, "logCollector", logCollector);
new NonStrictExpectations(archivingBean) {
{ //Lets fake the DB stuff.
invoke(archivingBean, "getConnection");result = connection;
connection.prepareStatement(anyString); result = prepStatement;
prepStatement.executeUpdate(); returns(Integer.valueOf(3), Integer.valueOf(0), Integer.valueOf(3));
}
};
new NonStrictExpectations(props) {
{ //This is important. The numbers will be used for one of each 4 submethods
props.getProperty(ArchivingHandlerBean.ARCHIVING_CREDMATURITY_OVER_IN_DAYS); result = "160";
props.getProperty(ArchivingHandlerBean.ARCHIVING_CREDHIST_AGE_IN_DAYS); result = "150";
props.getProperty(ArchivingHandlerBean.ARCHIVING_DEBTHIST_AGE_IN_DAYS); result = "140";
props.getProperty(ArchivingHandlerBean.ARCHIVING_LOG_AGE_IN_DAYS); result = "130";
}
};
new Expectations() {
{
Date expected = new Date(now - (160 * 24 * 60 * 60 * 1000));
invoke(archivingBean, "moveCreditBasic2Archive", expected);
expected = new Date(now - (150 * 24 * 60 * 60 * 1000));
invoke(archivingBean, "moveCreditHistory2Archive", expected);
expected = new Date(now - (999 * 24 * 60 * 60 * 1000));
invoke(archivingBean, "moveDebtorHistory2Archive", expected);
expected = new Date(now - (130 * 24 * 60 * 60 * 1000));
invoke(archivingBean, "moveLog2Archive", expected);
}
};
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(now);
Deencapsulation.invoke(archivingBean,"moveDataToArchive",cal, props);
}
@测试
public void testMoveData2Archive()引发异常{
现在的最终长度=123456789000升;
//使archivingBean可运行所必需的。
向量logCollector=新向量();
设置字段(archivingBean,“logCollector”,logCollector);
新的非严格测量(archivingBean){
{//让我们假装数据库的东西。
调用(archivingBean,“getConnection”);结果=连接;
connection.prepareStatement(anyString);result=prepStatement;
prepStatement.executeUpdate();返回(Integer.valueOf(3)、Integer.valueOf(0)、Integer.valueOf(3));
}
};
新的非科学观测(道具){
{//这很重要。数字将用于每4个子方法中的一个子方法
props.getProperty(ArchivingHandlerBean.ARCHIVING_CREDMATURITY_OVER_IN_DAYS);result=“160”;
props.getProperty(ArchivingHandlerBean.ARCHIVING_CREDHIST_AGE_IN_DAYS);result=“150”;
props.getProperty(ArchivingHandlerBean.ARCHIVING_debt hist_AGE_IN_DAYS);result=“140”;
props.getProperty(ArchivingHandlerBean.ARCHIVING_LOG_AGE_IN_DAYS);result=“130”;
}
};
新期望(){
{
预期日期=新日期(现在-(160*24*60*60*1000));
调用(archivingBean,“movecreditbasic2carchive”,应为);
预期=新日期(现在-(150*24*60*60*1000));
调用(archivingBean,“moveCreditHistory2Archive”,应为);
预期=新日期(现在-(999*24*60*60*1000));
调用(archivingBean,“movedebortorhistory2archive”,预期);
预期=新日期(现在-(130*24*60*60*1000));
调用(archivingBean,“moveLog2Archive”,应为);
}
};
Calendar cal=Calendar.getInstance();
cal.setTimeInMillis(现在);
调用(archivingBean,“moveDataToArchive”、cal、props);
}
有什么问题吗?请参阅第三个预期日期。这是错误的!(999而不是140)。
我还改变了通话顺序。我甚至公开了这些私人方法并尝试了它。所有这些变化并没有改变结果:测试是绿色的
这里怎么了?为什么测试是绿色的?该测试通过混合对同一模拟的严格和非严格期望而误用模拟API(
archivingBean
)。此模拟中记录的第一个预期是非严格的,因此JMockit将其视为整个测试的非严格模拟
编写测试的正确方法是在测试结束时将严格期望块(具有4个“sub方法”调用的块)转换为验证块
(顺便说一句,整个测试有几个问题。1)一般来说,私有方法应该通过一些公共方法间接测试。2) 此外,私有方法不应该被模仿,除非有强烈的理由——在本例中,我可能会编写一个测试来验证输出文件的实际内容。3) 不要不必要地模仿事物,比如props
-props。我想可以使用setProperty
。4) 使用自动装箱-Integer.valueOf(3)
->3
)。@Rogério:
你的假设并不完全有效。i、 e.我没有setProperty()。我尝试的是使用验证块
可悲的是,我不明白它是否足够好,让它运行
我做了两件事。首先,我试图模拟4个私有方法。我只想看看有没有人叫他们。但我不想让逻辑运行。
我尝试通过如下方式扩展第一个NonStrictExpections块:
new NonStrictExpectations(archivingBean) {
{
invoke(archivingBean, "getConnection");result = connection;
connection.prepareStatement(anyString); result = prepStatement;
prepStatement.executeUpdate(); returns(Integer.valueOf(3), Integer.valueOf(0), Integer.valueOf(3));
//New part
invoke(archivingBean, "moveCreditBasic2Archive", withAny(new Date()));
invoke(archivingBean, "moveCreditHistory2Archive", withAny(new Date()));
invoke(archivingBean, "moveDebtorHistory2Archive", withAny(new Date()));
invoke(archivingBean, "moveLog2Archive", withAny(new Date()));
}
};
另一方面,我将Expectations块向下移动,使其成为verifications块。现在JUnit失败了,出现了一个错误
mockit.internal.MissingInvocation: Missing invocation of:
de.lpm.ejb.archiving.ArchivingHandlerBean#moveCreditBasic2Archive(java.util.Date pOlderThan)
with arguments: Tue Feb 03 03:39:51 CET 2009
on mock instance: de.lpm.ejb.archiving.ArchivingHandlerBean@1601bde
at de.lpm.ejb.archiving.ArchivingHandlerBean.moveCreditBasic2Archive(ArchivingHandlerBean.java:175)
[...]
Caused by: Missing invocation
这是ArchivingHandlerBean.java中的第170-175行:
170: Connection connection = getConnection();
171: SQLService service = new SQLService(connection);
172:
173: PreparedStatement prepStmtMove = null;
174:
175: Vector<HashMap<String, String>> where_clauses = new Vector<HashMap<String,String>>();
170:Connection-Connection=getConnection();
171:SQLService=newsqlservice(连接);
172:
173:PreparedStatement prepstmove=null;
174:
175:向量,其中_子句=新向量();
我只是想验证4个私有方法是否在正确的日期执行。我试图将严格的期望更改为验证,但又出现了另一个错误。看我的“答案”是的,我的答案不是完全正确的,因为这个测试是部分模拟。因此,在这种情况下,需要首先记录期望值,以便JMockit知道不执行原始方法实现。稍后仍然可以编写一个验证块,以验证调用是否按预期进行,但这意味着测试中存在冗余代码。最后,由于需要调用/模拟私有方法,并且使用了部分模拟,因此模拟并不是这个测试的好选择。就我个人而言,我会使用完全不同的方法。你能描述一下你将如何测试这种情况吗?我会使用两种可能的替代方法之一:1)只使用外部输入(“道具”等)和输出(书面存档文件内容)编写黑盒测试,不使用模拟;或者2)编写一个真正的单元测试,通过与独立单元的交互来验证
archivingBean
行为(从archivingBean.moveDataToArchive
调用的私有方法中提取的新类)。