Correspondants d’arguments EasyMock

EasyMock Arguments Matchers

1. Vue d'ensemble

Dans ce didacticiel, nous allons explorer les correspondances d'arguments EasyMock. We’ll discuss different types of predefined matchers and how to create a custom matcher également.

Nous avons déjà couvert les bases d'EasyMock dans l'article deintroduction to EasyMock, vous devrez donc peut-être le lire d'abord pour vous familiariser avec EasyMock.

2. Exemple de simulation simple

Avant de commencer à explorer différentes correspondances, examinons notre contexte. Tout au long de ce didacticiel, nous utiliserons un service utilisateur assez basique dans nos exemples.

Voici notre interface simple deIUserService:

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

Et le modèleUser associé:

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

    // standard constructor, getters, setters
}

Nous allons donc commencer par nous moquer simplement de nosIUserService pour les utiliser dans nos exemples:

private IUserService userService = mock(IUserService.class);

À présent, explorons les correspondances d'arguments EasyMock.

3. Matchers d'égalité

Tout d'abord, nous allons utiliser le matchereq() pour faire correspondre les nouveauxUser ajoutés:

@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);
}

Ce matcher est disponible à la fois pour les objets primitifs et pour lesuses the equals() method for objects.

De même, nous pouvons utiliser le matchersame() pour faire correspondre unUser spécifique:

@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 “==”, ce qui signifie qu'il compare les instances deUser dans notre cas.

Si nous n'utilisons pas de correspondance, les arguments sont comparés par défaut à l'aide deequals().

Pour les tableaux, nous avons également le matcheraryEq() qui est basé sur la méthodeArrays.equals().

Correspondants4. Any

Il existe plusieurs correspondances quelconques commeanyInt(),anyBoolean(),anyDouble(),… etc. These specify that the argument should have the given type.

Voyons un exemple d'utilisation deanyString() pour faire correspondre leemail attendu à n'importe quelle valeur deString:

@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());
}

Nous pouvons également utiliserisA() pour faire correspondre un argument à une instance d'une classe spécifique:

@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);
}

Ici, nous affirmons que nous nous attendons à ce que le paramètre de méthodeaddUser() soit de typeUser.

5. Matchers nuls

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

Dans l'exemple suivant, nous utiliserons la correspondanceisNull() pour vérifier si la valeurUser ajoutée est nulle:

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

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

Nous pouvons également faire correspondrenotNull() si la valeur ajoutée de l'utilisateur n'est pas nulle de la même manière:

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

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

Correspondants6. String

Il existe plusieurs correspondants utiles que nous pouvons utiliser avec les argumentsString.

Tout d'abord, nous allons utiliser le matcherstartsWith() pour correspondre au préfixe de messagerie d'un utilisateur:

@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());
}

De même, nous utiliserons le matcherendsWith() pour le suffixe d'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());
}

Plus généralement, nous pouvons utilisercontains() pour faire correspondre l'e-mail avec une sous-chaîne donnée:

@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 même associez notre email à une expression régulière spécifique en utilisantmatches():

@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 numéros

Nous avons également quelques correspondants pour les valeurs numériques que nous pouvons utiliser.

Voyons un exemple d'utilisation du matcherlt() pour que l'argument age soit inférieur à 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());
}

De même, nous utilisons égalementgeq() pour que l'argument age soit supérieur ou égal à 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());
}

Les numéros disponibles sont:

  • lt() - inférieur à la valeur donnée

  • leq() - inférieur ou égal

  • gt() - supérieur à

  • geq() - supérieur ou égal

8. Combinez Matchers

Nous pouvons également combiner plusieurs correspondants en utilisant les correspondantsand(),or() etnot().

Voyons comment nous pouvons combiner deux correspondances pour vérifier que la valeur d'âge est à la fois supérieure à 10 et inférieure à 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());
}

Un autre exemple que nous pouvons examiner est la combinaison denot() avecendsWith() pour faire correspondre les e-mails qui ne se terminent pas par ".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 personnalisé

Enfin, nous verrons comment créer un correcteur EasyMock personnalisé.

Le but est de créer un simple correcteurminCharCount() pour faire correspondre les chaînes d'une longueur supérieure ou égale à la valeur donnée:

@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());
}

Pour créer un correcteur d'arguments personnalisé, nous devons:

  • créer une nouvelle classe qui implémente l'interfaceIArgumentMatcher

  • créer une méthode statique avec le nouveau nom du matcher et enregistrer une instance de la classe ci-dessus en utilisantreportMatcher()

Voyons les deux étapes de notre méthodeminCharCount() qui déclare une classe anonyme en son sein:

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;
}

Notez également que l'interfaceIArgumentMatcher a deux méthodes:matches() etappendTo(). 

La première méthode contient la validation d'argument et la logique de notre matcher, tandis que la seconde est utilisée pour ajouter la représentation du matcherString à imprimer en cas d'échec.

10. Conclusion

Nous avons présenté les correspondances d'arguments prédéfinies EasyMock pour différents types de données et la création de notre outil de correspondance personnalisé.

Le code source complet des exemples est disponibleover on GitHub.