[JAVA] Modèle de générateur de données de test ~ Améliore la maintenabilité du code de test

Cet article est le 17e jour du Calendrier de l'Avent Android 2 2016 - Qiita.

Aujourd'hui, comme l'un des modèles utiles pour maintenir le code de test, Je voudrais vous présenter le ** modèle Test Data Builder **.

supposition

Pendant le développement réel Vous écrirez souvent du code de test pour les classes qui utilisent des modèles (tels que des objets de valeur). Cette fois, en supposant un tel cas, l'objet de valeur est ʻUser, et la classe qui l'utilise est ʻUserRepository. Continuons avec l'histoire comme exemple.

User.java


//modèle
final class User {
  private final long id;
  private final String name;
  private final int age;
  private final Gender gender;
  private final String avatarUrl;
  private final Email email;

  User(long id, String name, int age, Gender gender,
      String avatarUrl, Email email) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.avatarUrl = avatarUrl;
    this.email = email;
  } 
}

UserRepository.java


//Classe à l'aide d'un modèle
class UserRepository {

  User findBy(long id) {
    return null; // TODO
  }

  List<User> findAll() {
    return null; // TODO
  }

  void store(User user) {
    // TODO
  }
}

Méthode d'essai sans motif

Quand j'essaye d'écrire ce test Repository, je pense qu'il ressemble à ceci:

UserRepository.java


public class UserRepositoryTest {
  private UserRepository repo;

  @Before public void setUp() {
    repo = new UserRepository();
  }

  @Test public void store() {
    long id = 100;
    User expected = new User(id, "", 1, Gender.MALE, "", new Email(""));

    repo.store(expected);

    User actual = repo.findBy(id);
    assertThat(actual, is(equalTo(expected)));
  }

  @Test public void findAll() {
    repo.store(new User(1, "", 1, Gender.MALE, "", new Email("")));
    repo.store(new User(2, "", 1, Gender.MALE, "", new Email("")));

    List<User> actual = repo.findAll();

    assertThat(actual.size(), is(2));
  }
}

problème

Je pense que le problème avec ce code de test est la ** partie d'instanciation de classe ʻUser` **. Voici pourquoi.

--ʻLe code est difficile à voir car il y a de nombreux arguments dans le constructeur de la classe User`.

Les deux peuvent être une responsabilité pour le fonctionnement à long terme du code de test.

Méthode de test utilisant des motifs

Pour résoudre les problèmes ci-dessus, nous préparerons une classe spécialisée dans la création de données pour la classe ʻUser` à des fins de test. Cela s'appelle le modèle ** Test Data Builder **.

Le fait est que ** les variables membres de cette classe ont des valeurs par défaut définies **.

UserDataBuilder.java


class UserDataBuilder {
  private long id = 1;
  private String name = "name";
  private int age = 20;
  private Gender gender = Gender.MALE;
  private String avatarUrl = "avatarUrl";
  private Email email = new EmailDataBuilder().build();

  public User build() {
    return new User(id, name, age, gender, avatarUrl, email);
  }

  public UserDataBuilder withId(long id) {
    this.id = id;
    return this;
  }

  public UserDataBuilder withName(String name) {
    this.name = name;
    return this;
  }

  ...réduction...

  public UserDataBuilder withEmail(Email email) {
    this.email = email;
    return this;
  }
}

En utilisant cette classe ʻUserDataBuilder`, si vous modifiez le code de test ci-dessus, ce sera comme suit.

UserRepositoryTest.java


public class UserRepositoryTest {
  private UserRepository repo;

  @Before public void setUp() {
    repo = new UserRepository();
  }

  @Test public void store() {
    long id = 100;
    User expected = new UserDataBuilder().withId(id).build();

    repo.store(expected);

    User actual = repo.findBy(id);
    assertThat(actual, is(equalTo(expected)));
  }

  @Test public void findAll() {
    UserDataBuilder user = new UserDataBuilder();
    repo.store(user.withId(1).build());
    repo.store(user.withId(2).build());

    List<User> actual = repo.findAll();

    assertThat(actual.size(), is(2));
  }
}

Le résultat de l'application du motif

Qu'est-ce que tu penses. Comparé au code de test qui n'utilise pas de modèles, ce code est

Je pense qu'il y a un tel mérite.

Résumé

La classe ʻUser` utilisée dans cet exemple était un objet relativement facile à instancier. Cependant, dans le développement réel, il existe de nombreuses classes dépendantes et de nombreux cas où il est difficile de préparer des données de test. À ce moment-là

Pour écrire le code de test Pourquoi ne pas appliquer ce ** modèle Test Data Builder **?

Les références

Recommended Posts

Modèle de générateur de données de test ~ Améliore la maintenabilité du code de test
Modèle de générateur de données de test ~ Améliore la maintenabilité du code de test
Modèle de constructeur
Modèle de constructeur
Modèle de conception ~ Constructeur ~
Modèle de conception (2): constructeur
String et stringbuffer et générateur de chaîne
Modèle de générateur (Java effectif)
Introduction à Effective Java en pratiquant et en apprenant (modèle Builder)
Modèle de constructeur
Modèle de constructeur
RSpec-Résultats de la révision du code de test pour la «validation des utilisateurs»
Modèle de conception ~ Constructeur ~
Modèle de conception (2): constructeur
Modèle de générateur qui force un ensemble de propriétés requises
Définir la source de données dans le code au lieu de la propriété dans spring-boot