【问题标题】:How to test with easymock Capture如何使用 easymock Capture 进行测试
【发布时间】:2009-12-01 13:24:07
【问题描述】:

我有以下代码

Record rd = registerNewRecord();
<do some processing>
rd.setFinished(true);
updateRecord(rd);

registerNewRecord方法调用RecordDao插入方法,updateRecord调用同一个DAO上的update方法。

我有以下easymock代码:

Capture<Record> insertRc = new Capture<Record>();
RecordDao.insert(capture(insertRc));
Capture<Record> updateRc= new Capture<Record>();
RecordDao.update(capture(updateRc));

问题是因为上面 rd 插入的同一 Record 实例正在更新,insertRc Capture 对象也正在更新。所以我不能断言完成标志在插入时设置为 false。

我做错了什么?

【问题讨论】:

    标签: java unit-testing easymock


    【解决方案1】:

    如果insertRCupdateRC 中的引用都引用了同一个对象rd,并且在update 方法期间发生了更改,您将始终看到Record 对象已完成。但是,您可以在调用 update 之前测试第一个 Captured 对象。

    Capture<Record> insertRc = new Capture<Record>();
    RecordDao.insert(capture(insertRc));
    Record insertedRecord = insertRC.getValue();
    org.junit.Assert.assertFalse(insertedRecord.isFinished());
    
    Capture<Record> updateRc= new Capture<Record>();
    RecordDao.update(capture(updateRc));
    Record updatedRecord = updateRC.getValue();
    org.junit.Assert.assertTrue(updatedRecord.isFinished());
    

    【讨论】:

      【解决方案2】:

      一个想法是在捕获 Record 对象时对其进行克隆。

      在您的 Record 类中实现 clone() 方法,然后按如下方式实现自定义 Capture:

      public class RecordCloneCapture extends Capture<Record> {
          @Override
          public void setValue(Record value) {
              super.setValue(value == null ? null : value.clone());
          }
      }
      

      并更改您的测试代码以使用它:

      Capture<Record> insertRc = new RecordCloneCapture();
      RecordDao.insert(capture(insertRc));
      Capture<Record> updateRc= new RecordCloneCapture();
      RecordDao.update(capture(updateRc));
      

      如果由于某种原因您无法实现 clone(),您的自定义 Capture 类可以在 setValue 方法中提取它需要的信息(即记录完成标志)并将其存储。

      【讨论】:

        【解决方案3】:

        捕获不是答案。问题是您的代码正在 registerNewRecord 中创建一个新对象(或者我认为如此)。在您正在测试的代码完成之前,无法获取您使用new 创建的对象。捕获允许您在被测方法完成后询问在执行期间创建/获得的对象的问题。

        您的测试的另一个问题是您对当前方法的测试取决于registerNewRecord() 方法中的代码,并且可能是Record 对象的构造函数中的任何代码。打破这种依赖关系并验证 Record 对象的中间状态的一种方法是存根 registerNewRecord() 方法并让它返回一个模拟。然后您可以测试是否对 Record 对象进行了正确的调用,并且您的代码对于来自 Record 对象的所有可能返回值的行为是否正确。

        MyClassStub extends MyClass {
          Record registerNewRecord() {
            return recordMock;
          }
        }
        
        MyClass objectToTest = new MyClassStub();
        
        public void testSomeMethod() {
           // set expectations, call replay
           objectToTest.someMethod();  // (contains above code that calls registerRecord)
           // asserts/verify
        }
        

        作为一个积极的副作用,您会发现您的测试仅在您正在测试的方法中的代码出现问题时才会中断,如果问题出在 Record 的构造函数或 registerNewRecord 中,则永远不会中断。但是,您需要为registerNewRecord() 方法编写第二个测试,以确保它正常工作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-05-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-27
          • 1970-01-01
          • 2011-07-18
          相关资源
          最近更新 更多