Correspondentes de argumento do EasyMock

Correspondentes de argumento do EasyMock

1. Visão geral

Neste tutorial, exploraremos os matchers de argumento do EasyMock. We’ll discuss different types of predefined matchers and how to create a custom matcher também.

Já cobrimos os fundamentos do EasyMock no artigointroduction to EasyMock, então você pode precisar lê-lo primeiro para se familiarizar com o EasyMock.

2. Exemplo de simulação simples

Antes de começarmos a explorar combinações diferentes, vamos dar uma olhada em nosso contexto. Ao longo deste tutorial, usaremos um serviço de usuário bastante básico em nossos exemplos.

Esta é a nossa interfaceIUserService simples:

public interface IUserService {
    public boolean addUser(User user);
    public List findByEmail(String email);
    public List findByAge(double age);
}

E o modeloUser relacionado:

public class User {
    private long id;
    private String firstName;
    private String lastName;
    private double age;
    private String email;

    // standard constructor, getters, setters
}

Então, vamos começar meramente zombando de nossoIUserService para usá-lo em nossos exemplos:

private IUserService userService = mock(IUserService.class);

Agora, vamos explorar os combinadores de argumento do EasyMock.

3. Equality Matchers

Primeiro, usaremos o matchereq() para corresponder ao novoUser adicionado:

@Test
public void givenUserService_whenAddNewUser_thenOK() {
    expect(userService.addUser(eq(new User()))).andReturn(true);
    replay(userService);

    boolean result = userService.addUser(new User());
    verify(userService);
    assertTrue(result);
}

Este matcher está disponível para primitivos e objetos, euses the equals() method for objects.

Da mesma forma, podemos usar o matchersame() para combinar umUser específico:

@Test
public void givenUserService_whenAddSpecificUser_thenOK() {
    User user = new User();

    expect(userService.addUser(same(user))).andReturn(true);
    replay(userService);

    boolean result = userService.addUser(user);
    verify(userService);
    assertTrue(result);
}

The same() matcher compares arguments using “==”, o que significa que compara instâncias deUser em nosso caso.

Se não usarmos correspondências, os argumentos são comparados por padrão usandoequals().

Para arrays, também temos o matcheraryEq() que é baseado no métodoArrays.equals().

4. Any Matchers

Existem vários matchers comoanyInt(),anyBoolean(),anyDouble(), ... etc. These specify that the argument should have the given type.

Vejamos um exemplo do uso deanyString() para combinar oemail esperado para ser qualquer valorString:

@Test
public void givenUserService_whenSearchForUserByEmail_thenFound() {
    expect(userService.findByEmail(anyString()))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByEmail("[email protected]");
    verify(userService);
    assertEquals(0,result.size());
}

Também podemos usarisA() para corresponder a um argumento para ser uma instância de uma classe específica:

@Test
public void givenUserService_whenAddUser_thenOK() {
    expect(userService.addUser(isA(User.class))).andReturn(true);
    replay(userService);

    boolean result = userService.addUser(new User());
    verify(userService);
    assertTrue(result);
}

Aqui, estamos afirmando que esperamos que o parâmetro do métodoaddUser() seja do tipoUser.

5. Null Matchers

A seguir,we can use the isNull() and notNull() matchers to match null values.

No exemplo a seguir, usaremos o matcherisNull() para corresponder se o valorUser adicionado for nulo:

@Test
public void givenUserService_whenAddNull_thenFail() {
    expect(userService.addUser(isNull())).andReturn(false);
    replay(userService);

    boolean result = userService.addUser(null);
    verify(userService);
    assertFalse(result);
}

Também podemosnotNull() para corresponder se o valor adicionado do usuário não for nulo de maneira semelhante:

@Test
public void givenUserService_whenAddNotNull_thenOK() {
    expect(userService.addUser(notNull())).andReturn(true);
    replay(userService);

    boolean result = userService.addUser(new User());
    verify(userService);
    assertTrue(result);
}

6. String Matchers

Existem vários matchers úteis que podemos usar com argumentosString.

Primeiro, usaremos o matcherstartsWith() para corresponder ao prefixo de e-mail de um usuário:

@Test
public void whenSearchForUserByEmailStartsWith_thenFound() {
    expect(userService.findByEmail(startsWith("test")))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByEmail("[email protected]");
    verify(userService);
    assertEquals(0,result.size());
}

Da mesma forma, usaremos o matcherendsWith() para o sufixo de e-mail:

@Test
public void givenUserService_whenSearchForUserByEmailEndsWith_thenFound() {
    expect(userService.findByEmail(endsWith(".com")))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByEmail("[email protected]");
    verify(userService);
    assertEquals(0,result.size());
}

De forma mais geral, podemos usarcontains() para combinar o e-mail com uma determinada substring:

@Test
public void givenUserService_whenSearchForUserByEmailContains_thenFound() {
    expect(userService.findByEmail(contains("@")))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByEmail("[email protected]");
    verify(userService);
    assertEquals(0,result.size());
}

Ou até mesmo associe nosso e-mail a um regex específico usandomatches():

@Test
public void givenUserService_whenSearchForUserByEmailMatches_thenFound() {
    expect(userService.findByEmail(matches(".+\\@.+\\..+")))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByEmail("[email protected]");
    verify(userService);
    assertEquals(0,result.size());
}

7. Matchers de números

Também temos alguns correspondentes para valores numéricos que podemos usar.

Vamos ver um exemplo de como usar o matcherlt() para fazer com que o argumento de idade seja menor que 100:

@Test
public void givenUserService_whenSearchForUserByAgeLessThan_thenFound() {
    expect(userService.findByAge(lt(100.0)))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByAge(20);
    verify(userService);
    assertEquals(0,result.size());
}

Da mesma forma, também usamosgeq() para fazer com que o argumento da idade seja maior ou igual a 10:

@Test
public void givenUserService_whenSearchForUserByAgeGreaterThan_thenFound() {
    expect(userService.findByAge(geq(10.0)))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByAge(20);
    verify(userService);
    assertEquals(0,result.size());
}

Os correspondentes de número disponíveis são:

  • lt() - menor que o valor fornecido

  • leq() - menor ou igual

  • gt() - maior que

  • geq() - maior ou igual

8. Combine Matchers

Também podemos combinar vários matchers usando matchersand(),or()enot().

Vejamos como podemos combinar dois matchers para verificar se o valor da idade é maior que 10 e menor que 100:

@Test
public void givenUserService_whenSearchForUserByAgeRange_thenFound() {
    expect(userService.findByAge(and(gt(10.0),lt(100.0))))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByAge(20);
    verify(userService);
    assertEquals(0,result.size());
}

Outro exemplo que podemos observar é combinarnot() comendsWith() para corresponder e-mails que não terminam com “.com”:

@Test
public void givenUserService_whenSearchForUserByEmailNotEndsWith_thenFound() {
    expect(userService.findByEmail(not(endsWith(".com"))))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByEmail("[email protected]");
    verify(userService);
    assertEquals(0,result.size());
}

9. Matcher personalizado

Finalmente, discutiremos como criar um matcher EasyMock personalizado.

O objetivo é criar um matcherminCharCount() simples para combinar strings com um comprimento maior ou igual ao valor fornecido:

@Test
public void givenUserService_whenSearchForUserByEmailCharCount_thenFound() {
    expect(userService.findByEmail(minCharCount(5)))
      .andReturn(Collections.emptyList());
    replay(userService);

    List result = userService.findByEmail("[email protected]");
    verify(userService);
    assertEquals(0,result.size());
}

Para criar um correspondente de argumento personalizado, precisamos:

  • crie uma nova classe que implemente a interfaceIArgumentMatcher

  • crie um método estático com o novo nome de correspondência e registre uma instância da classe acima usandoreportMatcher()

Vamos ver as duas etapas em nosso métodominCharCount() que declara uma classe anônima dentro dele:

public static String minCharCount(int value){
    EasyMock.reportMatcher(new IArgumentMatcher() {
        @Override
        public boolean matches(Object argument) {
            return argument instanceof String
              && ((String) argument).length() >= value;
        }

        @Override
        public void appendTo(StringBuffer buffer) {
            buffer.append("charCount(\"" + value + "\")");
        }
    });
    return null;
}

Além disso, observe que a interfaceIArgumentMatcher tem dois métodos:matches()eappendTo(). 

O primeiro método contém a validação do argumento e lógica para nosso matcher, enquanto o segundo é usado para anexar a representaçãoString do matcher a ser impressa em caso de falha.

10. Conclusão

Abordamos os correspondentes de argumentos predefinidos do EasyMock para diferentes tipos de dados e como criar nosso correspondente personalizado.

O código-fonte completo dos exemplos está disponívelover on GitHub.