I have the following code
Record rd = registerNewRecord();
<do some processing>
rd.setFi开发者_开发问答nished(true);
updateRecord(rd);
The registerNewRecord method calls the RecordDao insert method, and updateRecord calls the update method on the same DAO.
I have the following easymock code:
Capture<Record> insertRc = new Capture<Record>();
RecordDao.insert(capture(insertRc));
Capture<Record> updateRc= new Capture<Record>();
RecordDao.update(capture(updateRc));
Problem is since above rd the same instance of Record that was inserted is being updated, the insertRc Capture object is being updated too. So i cannot assert that the finished flag is set to false at insert time.
What am i doing wrong?
If the references within insertRC
and updateRC
both refer to the same object rd
and this is changed during the update
method, you will always see that the Record
object has finished. However, you could test the first Captured object before the update
call is made.
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());
One idea is to clone the Record object when you capture it.
Implement a clone()
method in your Record class, and then implement a custom Capture as follows:
public class RecordCloneCapture extends Capture<Record> {
@Override
public void setValue(Record value) {
super.setValue(value == null ? null : value.clone());
}
}
And change your test code to use it:
Capture<Record> insertRc = new RecordCloneCapture();
RecordDao.insert(capture(insertRc));
Capture<Record> updateRc= new RecordCloneCapture();
RecordDao.update(capture(updateRc));
If you can't implement clone()
for some reason, your custom Capture class could just extract the information it needs (i.e. the Record finished flag) in the setValue
method and store it.
Captures are not the answer. The problem is that your code is creating a new object in the registerNewRecord (or so I presume). There is no way to get the object you create with new
before the code you are testing completes. Captures allow you to ask questions of an object created/obtained during execution, AFTER the method under test completes.
Another problem with your test is that your test for the current method depends on the code in the registerNewRecord()
method and probably any code in the constructor of the Record object. One way to break this dependency and validate the intermediate state of the Record object is to stub out the registerNewRecord()
method and have it return a mock. Then you can test that the right calls were made to the Record object, and that your code behaves correctly for all possible return values from the record object.
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
}
As a positive side effect, you will find that your test only breaks when there is something wrong with the code in the method you are testing and never breaks if the problem lies in Record's constructor or registerNewRecord. You will however want to write a second test for the registerNewRecord()
method to ensure that it works properly.
精彩评论