-1

In my code I have

kiteOrderService.modifyOrder(params, profitBracketOrder.getOrder().orderId);

and another invocation at another place. Via stepping through I have verified that the first invocation params.price is 525 and for the second it is 475. Yet in the test code

verify(mockKiteOrderService, times(2)).modifyOrder(orderParamsArgumentCaptor.capture(), eq("3"));
List<OrderParams> orderParamsCaptured = orderParamsArgumentCaptor.getAllValues();
assertThat(orderParamsCaptured.get(0).price).isEqualTo(525.0); 
assertThat(orderParamsCaptured.get(1).price).isEqualTo(475.0);

orderParamsCaptured.get(0).price is 475 and this is the value captured for both invocations.

In my build.gradle I didn't have any mockito dependency specified, I have

testImplementation ('org.junit.vintage:junit-vintage-engine'){
    exclude group: 'org.hamcrest' , module :'hamcrest-core' 
}

I have also tried adding

testImplementation group: 'org.mockito', name: 'mockito-core', version: '5.3.1'

but it didn't make any difference. I don't know which mockito version is getting used, I'm pasting my build.gradle below:

dependencies {
implementation ('org.springframework.boot:spring-boot-starter-web')

implementation group: 'com.google.truth', name: 'truth', version: '1.1.3'

annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation ('org.junit.vintage:junit-vintage-engine'){
    exclude group: 'org.hamcrest' , module :'hamcrest-core' 
}

}

that may be relevant. My test is not a spring boot test but a normal Junit5 unit test has has the annotation

@ExtendWith(MockitoExtension.class)

Any help is much appreciated.

Walking Corpse
  • 107
  • 7
  • 31
  • 49
  • You really have to show the code surrounding `modifyOrder` and how `params` is instantiated. – knittl May 08 '23 at 06:58

2 Answers2

0

You are not passing the price to your method and the price is not captured. You are passing a reference to an OrderParams instance. If you modify this instance later, the changes will be reflected in the captured reference. ArgumentCaptors do not magically copy their captured objects, they only keep a reference to it.

Here's a simplified example:

final Service svc = mock(Service.class);
final Params captor = ArgumentCaptor.forClass(Params.class);

final Params params = new Params();
params.setPrice(42);

svc.process(params);
verify(svc).process(captor.capture());

params.setPrice(1337); // this changes the captured reference!

assertEquals(1337, captor.getValue().getPrice());

This has nothing to do with Mockito or ArgumentCaptors, but the way Java works.

Must-read: Is Java "pass-by-reference" or "pass-by-value"?

knittl
  • 246,190
  • 53
  • 318
  • 364
  • But before the 2nd invocation I'm not reusing the orderParams() object and modifying it, instead I'm creating a new instance. – Walking Corpse May 21 '23 at 13:48
  • I found that creating a separate Argumentcaptor to use for each invocaton's verification somehow captures the arguments correctly. – Walking Corpse May 21 '23 at 14:27
0

I found that creating a separate Argumentcaptor to use for each verification somehow captures the arguments correctly.

Walking Corpse
  • 107
  • 7
  • 31
  • 49