The purpose of this post is simply to give a hint on how to use Mockito, Spy, and JUnit 5.
package se.tkartor.microservice.tols;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class MockTest {
@Mock
Car mockCarTWO;
@Test
public void noMockJustAssertTest() {
Car car = new Car("red", 250, new Wheels(19));
Assertions.assertEquals(250, car.maxSpeed);
}
/**
* The purpose of this test is to show that a Mock can be created
* using the API and does not have to be created using the @Mock annotation
* NOTE! that creating a mock out of a class, means that it still serves
* the interface/API of the original class, but NONE of the methods
* will do anything nor will the return anything
* The mock-instance is simply an empty shell, and hence the last
* commented-out code/line is not possible, since it will return NULL
*/
@Test
public void mockitoAPItest() {
Car mockCar = Mockito.mock(Car.class);
mockCar.setColor("blue");
mockCar.setMaxSpeed(100);
Mockito.verify(mockCar).setColor("blue");
// Assertions.assertEquals("blue" , mockCar.getColor());
Assertions.assertNull( mockCar.getColor() );
}
/**
* Based on the fact that a mocked class is an empty shell
* it is possible to also attach a.k.a spy on a instance
* and carry out mocking this way, this is useful when you have
* and instance that does everything right, except you need to
* see what happens when you demand it to return a certain value
* under certain cirumstances. The example below hopefully
* explains this :-)
*/
@Test
public void spyTest() {
Car mockCar = Mockito.spy(new Car("red", 90, new Wheels(19)));
mockCar.setColor("blue");
mockCar.setMaxSpeed(100);
Mockito.verify(mockCar).setColor("blue");
Assertions.assertEquals("blue", mockCar.getColor());
}
/**
* Nothing new, as explained above
* the instance of the mocked class will be an empty shell
*/
@Test
public void mockitoAPITest() {
Car mockCar = Mockito.mock(Car.class);
Mockito.when(mockCar.getColor()).thenReturn("green");
mockCar.setColor("blue");
mockCar.setMaxSpeed(100);
mockCar.setWheels(new Wheels(19)); // this is possible since the api signature is there and hence the mock
// allows it to be called, but it does not do anything
Mockito.verify(mockCar).setColor("blue");
Assertions.assertEquals("green", mockCar.getColor());
Assertions.assertNull(mockCar.getWheels()); // This is null, since there is no mock for it
}
/**
* The purpose with this test was simply
* to use the @Mock annotation insead of the
* mockito API, a somewhat lightweight / easy to read approach
*/
@Test
public void mockitoAnnotationTest() {
Mockito.when(mockCarTWO.getColor()).thenReturn("green");
Assertions.assertEquals("green", mockCarTWO.getColor());
}
public static class Wheels {
private int size;
public Wheels(int size) {
this.size = size;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
public static class Car {
private String color;
private long maxSpeed;
private Wheels wheels;
public Car(String color, long maxSpeed, Wheels wheels) {
this.color = color;
this.maxSpeed = maxSpeed;
this.wheels = wheels;
}
public int wheelSize() {
return wheels.getSize();
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public long getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(long maxSpeed) {
this.maxSpeed = maxSpeed;
}
public Wheels getWheels() {
return wheels;
}
public void setWheels(Wheels wheels) {
this.wheels = wheels;
}
}
}