Buscar..


Simulacro simple

Mockito ofrece un mehtod de talla única para crear simulacros de clases e interfaces (no finales).

Dependency mock = Mockito.mock(Dependency.class);

Esto crea una instancia simulada de Dependency independientemente de si la Dependency es una interfaz o una clase.

Entonces es posible aplazar las llamadas de método a ese simulacro usando la notación Mockito.when (x) .thenReturn (y).

Mockito.when(mock.possiblyBuggyMethod()).thenReturn("someString");

Así que las llamadas a Dependency.possiblyBuggyMethod() simplemente devuelven "someString" .

Hay otra notación que se desaconseja en la mayoría de los casos de uso, ya que no es de tipo seguro.

Mockito.doReturn("someString").when(mock).possiblyBuggyMethod()

Simulacros de impagos

Mientras que un simulacro simple devuelve nulo (o valores predeterminados para primitivas) a cada llamada, es posible cambiar ese comportamiento.

Dependency mock = Mockito.mock(Dependency.class, new Answer() {

        @Override
        public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
            return "someString";
        }
    });

o usando lambdas:

Dependency mock = Mockito.mock(Dependency.class, (Answer) invocationOnMock -> "someString");

Este ejemplo devuelve "someString" a cada invocación, pero es posible definir cualquier lógica en el método de respuesta.

Burlándose de una clase usando anotaciones

Clase a prueba:

public class GreetingsService { // class to be tested in isolation
    private UserService userService;

    public GreetingsService(UserService userService) {
        this.userService = userService;
    }

    public String getGreetings(int userId, LocalTime time) { // the method under test
        StringBuilder greetings = new StringBuilder();
        String timeOfDay = getTimeOfDay(time.getHour());
        greetings.append("Good ").append(timeOfDay).append(", ");
        greetings.append(userService.getFirstName(userId)) // this call will be mocked
                .append(" ")
                .append(userService.getLastName(userId)) // this call will be mocked
                .append("!");
        return greetings.toString();
    }

    private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
        if (hour >= 0 && hour < 12)
            return "Morning";
        else if (hour >= 12 && hour < 16)
            return "Afternoon";
        else if (hour >= 16 && hour < 21)
            return "Evening";
        else if (hour >= 21 && hour < 24)
            return "Night";
        else
            return null;
    }
}

El comportamiento de esta interfaz será burlado:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

Supongamos la implementación real del UserService :

public class UserServiceImpl implements UserService {
    @Override
    public String getFirstName(int userId) {
        String firstName = "";
        // some logic to get user's first name goes here
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return firstName;
    }

    @Override
    public String getLastName(int userId) {
        String lastName = "";
        // some logic to get user's last name goes here
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return lastName;
    }
}

Prueba de Junit con Mockito:

public class GreetingsServiceTest {
    @Mock
    private UserServiceImpl userService; // this class will be mocked
    @InjectMocks
    private GreetingsService greetingsService = new GreetingsService(userService);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetGreetings_morning() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(99)).thenReturn("John");
        when(userService.getLastName(99)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
        Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe!", greetings);
    }

    @Test
    public void testGetGreetings_afternoon() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(11)).thenReturn("Jane");
        when(userService.getLastName(11)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
        Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe!", greetings);
    }
}

"Spy" para burlarse parcialmente

La anotación (o método ) de @Spy se puede utilizar para simular parcialmente un objeto. Esto es útil cuando desea simular parcialmente el comportamiento de una clase. Por ejemplo, suponga que tiene una clase que utiliza dos servicios diferentes y desea burlarse solo de uno de ellos y usar la implementación real del otro servicio.

Nota al margen: aunque filosóficamente no consideraría esto como una "prueba de unidad pura" en un verdadero sentido, ya que está integrando una clase real y no está probando su clase bajo prueba en completo aislamiento. Sin embargo, esto podría ser realmente útil en el mundo real y a menudo lo uso cuando me burlo de la base de datos utilizando alguna implementación de base de datos en memoria para poder usar DAO reales.

Class under test:
public class GreetingsService { // class to be tested in isolation
    private UserService userService;
    private AppService appService;

    public GreetingsService(UserService userService, AppService appService) {
        this.userService = userService;
        this.appService = appService;
    }

    public String getGreetings(int userId, LocalTime time) { // the method under test
        StringBuilder greetings = new StringBuilder();
        String timeOfDay = getTimeOfDay(time.getHour());
        greetings.append("Good ").append(timeOfDay).append(", ");
        greetings.append(userService.getFirstName(userId)) // this call will be mocked
                .append(" ")
                .append(userService.getLastName(userId)) // this call will be mocked
                .append("!");
        greetings.append(" Welcome to ")
                .append(appService.getAppName()) // actual method call will be made
                .append(".");
        return greetings.toString();
    }

    private String getTimeOfDay(int hour) { // private method doesn't need to be unit tested
        if (hour >= 0 && hour < 12)
            return "Morning";
        else if (hour >= 12 && hour < 16)
            return "Afternoon";
        else if (hour >= 16 && hour < 21)
            return "Evening";
        else if (hour >= 21 && hour < 24)
            return "Night";
        else
            return null;
    }
}

El comportamiento de esta interfaz será burlado:

public interface UserService {
    String getFirstName(int userId);

    String getLastName(int userId);
}

Supongamos la implementación real del UserService :

public class UserServiceImpl implements UserService {
    @Override
    public String getFirstName(int userId) {
        String firstName = "";
        // some logic to get user's first name
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return firstName;
    }

    @Override
    public String getLastName(int userId) {
        String lastName = "";
        // some logic to get user's last name
        // this could be anything like a call to another service,
        // a database query, or a web service call
        return lastName;
    }
}

El comportamiento de esta interfaz no será burlado:

public interface AppService {
    String getAppName();
}

Supongamos la implementación real de AppService :

public class AppServiceImpl implements AppService {
    @Override
    public String getAppName() {
        // assume you are reading this from properties file
        String appName = "The Amazing Application";
        return appName;
    }
}

Prueba de Junit con Mockito:

public class GreetingsServiceTest {
    @Mock
    private UserServiceImpl userService; // this class will be mocked
    @Spy
    private AppServiceImpl appService; // this class WON'T be mocked
    @InjectMocks
    private GreetingsService greetingsService = new GreetingsService(userService, appService);

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testGetGreetings_morning() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(99)).thenReturn("John");
        when(userService.getLastName(99)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(99, LocalTime.of(0, 45));
        Assert.assertEquals("Failed to get greetings!", "Good Morning, John Doe! Welcome to The Amazing Application.", greetings);
    }

    @Test
    public void testGetGreetings_afternoon() throws Exception {
        // specify mocked behavior
        when(userService.getFirstName(11)).thenReturn("Jane");
        when(userService.getLastName(11)).thenReturn("Doe");
        // invoke method under test
        String greetings = greetingsService.getGreetings(11, LocalTime.of(13, 15));
        Assert.assertEquals("Failed to get greetings!", "Good Afternoon, Jane Doe! Welcome to The Amazing Application.", greetings);
    }
}

Establecer campos privados en objetos simulados.

En su clase que está bajo prueba, puede tener algunos campos privados que no son accesibles incluso a través del constructor. En tales casos, puede utilizar la reflexión para establecer dichas propiedades. Este es un fragmento de dicha prueba JUnit.

@InjectMocks
private GreetingsService greetingsService = new GreetingsService(); // mocking this class

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
    String someName = "Some Name";
    ReflectionTestUtils.setField(greetingsService, // inject into this object
        "name", // assign to this field
        someName); // object to be injected
}

Estoy usando de Sptring ReflectionTestUtils.setField(Object targetObject, String name, Object value) método aquí para simplificar, pero se puede usar el viejo y simple reflexión de Java para hacer lo mismo.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow