I have the following methods
//my method
public Car polishCar(Car car){
car.setPolish(true);
car.setPolishDate(new Date());
return car;
}
//myMethod
public Car washCar(Car car){
car.setWash(true);
car.setWashDate(new Date());
return car;
}
// mainMethod
public Car serviceCar(){
Car car = new Car();
myMethod.polishCar(car);
myMethod.washCar(car);
......
return Car;
}
This is what I have code for my unit test with mockito, I need to create 2 different Car objects which look redundant and keep adding new value to it.
Car pCar = new Car();
pCar.setPolish(true);
pCar.setPolishDate(new Date());
//first call
when(myMethod.polishCar(any(Car.class))).thenReturn(pCar);
Car wCar = new Car();
wCar.setPolish(true);
wCar.setPolishDate(new Date());
wCar.setWash(true);
wCar.setWashDate(new Date());
//second call with same car object from previous, and return same car object with additional value
when(myMethod.washCar(eq(pCar))).thenReturn(wCar);
Car testCar = mainMethod.serviceCar();
// check if they are same instance
assertEquals(testCar, wCar);
assertEquals("true", wCar.getWash());
assertEquals("true", wCar.polish());
How can I better handle this scenario to make mockito return the same & updated object (same instance) and keep passing to the next method call?
So the main point is I want to have 1 car object and this car object will pass to number of method to update this car object.
// Create 1 car object
Car singleCar = new Car();
//pass to first method, and return singleCar with updated polish & polishDate
when(myMethod.polishCar(eq(singleCar))).thenReturn(singleCar);
//pass to second method, and return singleCar with updated wash and washDate
when(myMethod.washCar(eq(singleCar))).thenReturn(singleCar);
// call main method for testing
Car testCar = mainMethod.serviceCar();
// assert testCar == singleCar
// assert singleCar is updated (wash == true & polish == true)
Is there any way to reuse the same object here ?
Thank you.
CodePudding user response:
There is no sense to use mock in this case. Just create a real SUT and the real car. Simply call the test method for the real car instance and directly verify the car 's state.
@Test
public polishAndCarTest(){
Car car = new Car();
Date now = new Date();
sut.polishCar(car);
sut.washCar(car);
assertThat(car.isPolish()).isTrue();
assertThat(car.getPolishDate()).isCloseTo(now,2);
assertThat(car.isWash()).isTrue();
assertThat(car.getWashDate()).isCloseTo(now,2);
}
Notes :
It is better that you can refactor
polishCar()
andwashCar()
such that it can accept a given date as the input argument rather than hardcode it as the current time . After that , you can pass a testing date when calling these methods in the test case and can easily verify the polish date and wash date is really updated to this date.If you don't like this , you can use assertj to verify these date is close to within 2 millisecond after the moment when
polishCar()
/washCar()
is called which is fine enough to me.
CodePudding user response:
Use any
Matcher like any(ParamClass.class)
.
In your case when(myMethod.washCar(any(Car.class))).thenReturn(wCar);
CodePudding user response:
You can use an ArgumentCaptor to capture the argument(your mock instance pCar). Then use that value in your test. Below is pseudo code but essentially how argueMent captor works
@Mock
Car pcar;
@Captor
ArgumentCaptor<Car> carCaptor;
when(myMethod.polishCar(
any(Car.class))).thenReturn(pCar);
Mockito.verify(car)
.polishCar(carCaptor.capture());
The captured argument would be the pCar which you can then use through out the test