Search code examples
javaunit-testingjunitjunit4junit5

Class has to create new object internally, which can't be accessed from unit test


We have a class whose purpose is to change the values in some fields of a received object and keep the values of its other fields

public void process(SomeType someObject) {
  SomeType modifiedObject = modifyObject(someObject);
  nextClass.process(modifiedObject);
}

private SomeType modifyObject(SomeType someObject) {
  String someValueFromServiceCall = someService.getSomeValue(...);
  SomeType modifiedObject = new SomeType.Builder()
                                        .withSomeFieldValuesFromSomeObjectItself(...)
                                        .withSomeFieldValuesFromServiceCall(someValueFromServiceCall)
                                        .build();
  return modifiedObject;
}

SomeType is a legacy class which we can create using only its builder class and it has no setter methods. This means we cannot modify the received someObject itself, but have to build and return a new SomeType object from modifyObject(), which the main method then can pass on for processing to the next class

However this seems to raise problems during unit testing. We don't seem to be able to access the internal modifiedObject from the unit test class and such as we don't seem to be able to do expects/asserts on it

SomeType someObject = createSomeObjectForTest();
expect(someServiceMock.getSomeValue(...)).andReturn(SOME_VALUE);
expect(nextClassMock.process(someObject)).andReturn(...); //this is not someObject, but the new internal modifiedObject created within underTest
underTest.process(someObject);
assertEquals(someObject.getSomeField(), SOME_VALUE); //this is not someObject, but the new internal modifiedObject created within underTest

Solution

  • Here's how to use the ArgumentCaptor:

    // mock and make sure all fields required for modify are set
    SomeType arg = create(); 
    ArgumentCaptor<SomeType> captor = ArgumentCaptor. forClass(SomeType.class);
    
    sut.process(arg) ;
    
    verify (nextClass). process(captor.capture());
    SomeType modified = captor.get();