Java JMockit-忽略严格期望

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

我想测试私有方法的行为。 方法“moveDataToArchive”执行4个步骤

它是4x:计算日期+调用子方法

这是我的测试:

@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
调用的私有方法中提取的新类)。