0

I have these two methods in my Java class:

public CancelOrder generateCancelOrder(
  final CurrentState currentState,
  final Contract contract) {

    Context ctx = new Context();
    ctx.setVariable(
        ORDER_STATE_NOW, trans(currentState, contract));

    PennyOrderDetails pennyCancelOrderDetails =
        pennyCancelOrderService.requestCancelOrder(ctx);

    return CancelOrderResponse.builder()
        .premiumSummary(pennyCancelOrderDetails.getOrderSummary())
        .build();
}

private QuoteMessageCurrentState transform(
  final CurrentState currentState, final Contract contract) {
return QuoteMessageCurrentState.builder()
    .fromRequest(messageTemplateChanges.change(currentState, contract))
    .extras(
        VoluntaryExtras.calculateVoluntaryExtrasAmount(currentState.getVoluntaryExtras()))
    .build();
}

extras is a string value. Is there any way I can unit test this that I can confirm what that value is so as to ensure a value is returned for this and that it is the correct value?

I'm aware that private methods shouldn't be unit tested. I recently encountered an issue where the line .extras(VoluntaryExtras.calculateVoluntaryExtrasAmount(currentState.getVoluntaryExtras())) was missing but it wasn't picked up until an an issue was detected by a downstream application. I'd like to put something in place where if this was accidentally removed, it would not go unnoticed.

runnerpaul
  • 5,942
  • 8
  • 49
  • 118
  • 3
    Private methods are part of the implementation. They are not unit tested. Or, more accurately, they are unit tested indirectly by unit testing the public methods which rely on the private methods. – Slaw Mar 09 '23 at 19:04
  • Regarding your edit: If a downstream application detected the issue, then presumably there is some sort of state involved that you could test for in the unit test. In other words, that `extras` call must have a visible side-effect that you can make assertions about. – Slaw Mar 09 '23 at 21:25
  • You can`verify(pennyCancelOrderService) .requestCancelOrder(ctxCaptor.capture())` with an appropriate `ArgumentCaptor` and then assert that the passed context contains the expected data. – daniu Mar 10 '23 at 21:50

3 Answers3

1

I recently encountered an issue where the line .extras(VoluntaryExtras.calculateVoluntaryExtrasAmount(currentState.getVoluntaryExtras())) was missing but it wasn't picked up until an an issue was detected by a downstream application. I'd like to put something in place where if this was accidentally removed, it would not go unnoticed.

What was the issue the downstream application encountered? Presumably there is some external state (perhaps the very CancelOrder object being returned) that is effected by the addition or removal of that line. Test that.

In other words:

@Test
public void generateCancelOrder() {
   // TODO: Get current state of the world before method is called
  
   CurrentState state = createDummyCurrentState();
   Contract contract = createDummyContract();
   CancelOrder order = generateCancelOrder(state, contract);
   
   // Assert expected state on state, contract, order, some other object, or any combination of all of the above
}
   
dominicoder
  • 9,338
  • 1
  • 26
  • 32
0

I added a test check that VoluntaryExtras.calculateVoluntaryExtrasAmount(currentState.getVoluntaryExtras() was called once when generateCancelOrder() was run.

runnerpaul
  • 5,942
  • 8
  • 49
  • 118
  • Is that really what you want to test, though? If someone edits the private method to call `VoluntaryExtras.calc...` but not store the result in `.extras(...)`, your test will pass but your code will fail. You should test the _expected final state / result_ of calling the method, not the _implementation details_ of the method. – dominicoder Mar 16 '23 at 15:49
-1

As correctly suggested by @Slaw private methods cannot be unit test. Instead of unit testing another approach can be to have validation in place. The constructor is where the validation occurs. Even when you're not using the builder pattern, constructors are responsible for ensuring that the object is in a valid state when it is created.

It has been explained in detail in stackoverflow thread Builder pattern validation - Effective Java