I. Introduction▲
Nos programmes utilisent de nombreux POJO : Plain Old Java Objects. Ces beans très simples sont généralement constitués d'attributs privés, parfois marqués « final », qu'on manipule via des getters et des setters. Pour des raisons pratiques, certains sont équipés de constructeurs reprenant lesdits attributs, en plus du constructeur par défaut. Et pour compléter le tout, on leur ajoute souvent les méthodes equals, hashCode et toString, héritées de Object.
La plupart des IDE (Eclipse, Idea, etc.) permettent d'ajouter toutes ces méthodes (getters, setters, constructeurs, equals, hashCode et toString) aux beans en quelques clics, si bien que la plupart des développeurs considèrent les POJO comme des beans de second plan. On les croit fiables. On n'y prête pas attention. On les ignore même dans les tests. C'est bien entendu une erreur, car de nombreux problèmes peuvent en résulter, mais qui lancera la première pierre ?
La bibliothèque Pojo-Tester, sous licence GNU GPL 3, s'intéresse spécifiquement à ces beans. Elle offre des mécanismes simples et efficaces pour les tester de fond en comble.
Pourquoi allez-vous donc utiliser Pojo-Tester ? À quoi cette bibliothèque va-t-elle vous servir ? D'abord à augmenter le score de votre couverture de code, même si c'est superficiel. Ensuite, et surtout, à sécuriser les méthodes de vos beans qui serait quasiment intestables sans. Pensez, par exemple, aux mauvais copiés-collés dans vos getters/setters ou dans l'enchaînement d'égalité de la méthode equals. Considérez aussi l'ajout d'un attribut, après coup, qui aurait été pris en compte dans equals, mais oublié dans hashCode. C'est une véritable galère d'identifier ce genre de bogue…
II. Projet d'exemple▲
Voici quelques éléments vraiment triviaux qui vont nous permettre d'illustrer le fonctionnement de la bibliothèque Pojo-Tester à moindre coût. Les codes complets sont proposés en annexes. Le projet dvp-article-pojo-tester est également disponible sur GitHub.
II-A. Bean et service▲
Pour commencer, disons que nous avons un bean Chien contenant quelques attributs (cf. ci-dessous). Pour faire bonne mesure, on demande à Eclipse de générer les méthodes hashCode, equals et toString, ainsi que les getters et les setters :
public class Chien {
private String name;
private String race;
private double poids; // Poids en kg
private double taille; // Taille exprimee en metre
private Date dateNaissance;
private List<String> couleurs;
public Chien() {
}
// + Getters / Setters
// + hashCode / equals
// + toString
...Juste pour l'exemple, disons qu'on écrit ChienService, une classe proposant un ensemble de fonctionnalités liées aux chiens.
public class ChienService {
public int calculerIMC(final Chien chien) {
return (int) (chien.getPoids() / Math.pow(chien.getTaille(), 2));
}
...II-B. Maven▲
Dans notre projet Maven, on indique une dépendance vers JUnit puisqu'on va écrire des tests.
<project ...>
...
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>On ajoute aussi une dépendance vers Jacoco, une bibliothèque (similaire à Cobertura) permettant de mesurer la couverture de code de notre programme.
<project ...>
...
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule implementation="org.jacoco.maven.RuleConfiguration">
<element>BUNDLE</element>
<limits>
<limit implementation="org.jacoco.report.check.Limit">
<counter>COMPLEXITY</counter>
<value>COVEREDRATIO</value>
<minimum>0.70</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>Cette configuration indique qu'on attend une couverture d'au moins 70 %, faute de quoi le build Maven se terminera en erreur.
II-C. Tests évidents▲
Pour tester convenablement l'objet Chien, il ne faudrait pas moins de huit tests. Pour l'instant on va donc seulement se concentrer sur le service. Voici le genre de test qu'on pourrait écrire :
public class ChienServiceTest {
private ChienService chienService = new ChienService();
@Test
public void testCalculerIMCMilou() {
// Arrange
final double taille = 0.39;
final double poids = 9;
final int expectedIMC = 59;
// Arrange obj
final Chien milou = new Chien();
milou.setTaille(taille);
milou.setPoids(poids);
// Act
final int imc = chienService.calculerIMC(milou);
// Assert
Assert.assertEquals(expectedIMC, imc);
}C'est le formalisme AAA (Arrange, Act and Assert), si cher à votre serviteur, qui est utilisé ici.
Voici, ci-dessous, les rapports de Jacoco à propos de la couverture du code à ce stade :
III. Action▲
On va maintenant s'occuper des POJO de notre programme.
III-A. Ajouter Pojo-Tester▲
Pour commencer, on ajoute la dépendance à Pojo-Tester :
<project ...>
...
<dependencies>
...
<dependency>
<groupId>pl.pojo</groupId>
<artifactId>pojo-tester</artifactId>
<version>0.7.5</version>
</dependency>
</dependencies>On aura également besoin de préciser le repository où trouver la bibliothèque Pojo-Tester :
<project ...>
...
<repositories>
<repository>
<id>jcenter</id>
<url>http://jcenter.bintray.com/</url>
</repository>
</repositories>III-B. Bean classique : Chien▲
Le bean Chien, qui représente sans aucun doute le cas le plus classique, est facile à tester :
import static pl.pojo.tester.api.assertion.Assertions.assertPojoMethodsFor;
public class AnimalTest {
@Test
public void testPojoChien() {
// Arrange
final Class<?> classUnderTest = Chien.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.areWellImplemented();
}Voici, ci-dessous, ce que ça donne au niveau de la couverture du code avec Jacoco. On constate que toutes les méthodes ont bien été couvertes (avec un petit raté sur equals). Magique, facile ?
À cette date, la bibliothèque a encore du mal a bien tester ma méthode equals. Il reste des instructions non couvertes. Espérons que les futures versions fassent évoluer le sujet.
Ajoutons maintenant le nouvel attribut « méchant » au bean Chien et demandons à Eclipse d'en générer le getter et le setter. Ici on va faire exprès d'oublier de faire évoluer equals, hashCode et toString.
public class Chien {
...
private boolean mechant; // juste getter/setter
...
public boolean isMechant() {
return mechant;
}
public void setMechant(boolean mechant) {
this.mechant = mechant;
}Là, Pojo-Tester va nous rappeler à l'ordre ; un oubli est vite arrivé et peut passer longtemps inaperçu. Charge ensuite au développeur de choisir quoi faire en piochant dans les techniques abordées dans les prochains chapitres.
Class com.dvp.tld.article.pojotester.domaine.Chien has bad 'toString' method implementation.
The toString method should contain:
mechant=false
But does not.
Result of toString:
Chien [name=null, race=null, poids=0.0, taille=0.0, dateNaissance=null, couleurs=null]III-C. Bean immutable : Lapin▲
Ajoutons maintenant le bean Lapin ayant la particularité de posséder des attributs marqués « final ». Ça change quelque peu la donne.
public class Lapin {
// Attributs final
private final String name;
private final int age;
// + Getters
// + hashCode / equals
// + toString
...Le bean Lapin n'a pas de setter puisque tous ses attributs sont « final ».
Essayons d'appliquer la même stratégie que pour le bean Chien :
public class AnimalTest {
@Test
public void testPojoLapinFailed() {
// Arrange
final Class<?> classUnderTest = Lapin.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.areWellImplemented();
}Le test échoue naturellement puisque Pojo-Tester ne trouve pas de setter :
Tests in error:
testPojoLapinFailed(...AnimalTest): Class ...Lapin has no setter for field private final ...String ...Lapin.nameLes noms de classes et d'attributs ont été tronqués dans le message d'erreur ci-dessus pour en faciliter la lecture.
Il faut donc préciser les méthodes qu'on souhaite tester :
import static pl.pojo.tester.api.assertion.Method.CONSTRUCTOR;
import static pl.pojo.tester.api.assertion.Method.EQUALS;
import static pl.pojo.tester.api.assertion.Method.GETTER;
import static pl.pojo.tester.api.assertion.Method.HASH_CODE;
import static pl.pojo.tester.api.assertion.Method.SETTER;
import static pl.pojo.tester.api.assertion.Method.TO_STRING;
public class AnimalTest {
@Test
public void testPojoLapin() {
// Arrange
final Class<?> classUnderTest = Lapin.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.testing(GETTER) //
.testing(TO_STRING) //
.testing(EQUALS, HASH_CODE) //
.testing(CONSTRUCTOR) //
.areWellImplemented();
}Ici, EQUALS et HASH_CODE sont sur la même ligne (dans la même instruction) pour insister sur le fait que les deux méthodes associées fonctionnent en paire. Elles doivent respecter le même contrat. Par extension, cela doit se traduire aussi dans les tests.
Et là ça fonctionne, comme on peut le voir sur le rapport de Jacoco :
III-D. Bean semi-immutable : Chat▲
On va compliquer encore les choses avec le bean Chat dans lequel seuls les attributs « name » et « age » sont pris en compte pour le constructeur et les méthodes hashCode et equals :
public class Chat {
// Attributs principaux (dans cons, hashcode et equals)
private final String name;
private final int age;
// Attributs en plus
private double poids;
private String moustache;
private String[] petits;
public Chat(String name, int age) {
super();
this.name = name;
this.age = age;
}
// + Getters / Setters
// + hashCode / equals
// + toString
...Si on tente de tester Chat comme on l'avait fait avec Lapin, ça ne va évidemment pas être bon :
public class AnimalTest {
@Test
public void testPojoChatFailed() {
// Arrange
final Class<?> classUnderTest = Chat.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.testing(GETTER) //
.testing(TO_STRING) //
.testing(EQUALS, HASH_CODE) //
.testing(CONSTRUCTOR) //
.areWellImplemented();
}Le build Maven va en effet nous donner l'erreur suivante, indiquant que la méthode hashCode n'est pas correcte. Notez que le test s'arrête à la première erreur sans rien dire des éventuelles autres erreurs :
Class ...Chat has bad 'hashCode' method implementation.
The hashCode method should return different hash codes for non equal objects.
Current implementation returns same hash codes.
Object:
Chat [name=www.pojo.pl, age=-4, poids=0.0, moustache=null, petits=null]
and
Chat [name=www.pojo.pl, age=-4, poids=-2.5, moustache=null, petits=null]
should have different hash codes:
1122311828
and
1122311828Il faut donc préciser les attributs qu'on souhaite prendre en compte pour chaque méthode, ce qui donne lieu à plusieurs appels dans le test. Ici on parlera d'inclusion :
import static pl.pojo.tester.api.FieldPredicate.include;
public class AnimalTest {
@Test
public void testPojoChatInclude() {
// Arrange
final Class<?> classUnderTest = Chat.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest, include("name", "age")) //
.testing(EQUALS, HASH_CODE) //
.testing(CONSTRUCTOR) //
.areWellImplemented();
assertPojoMethodsFor(classUnderTest, include("poids", "moustache", "petits")) //
.testing(SETTER) //
.areWellImplemented();
assertPojoMethodsFor(classUnderTest) //
.testing(GETTER) //
.testing(TO_STRING) //
.areWellImplemented();
}Ce n'est pas très pratique de fonctionner par inclusion. La bibliothèque permet aussi de travailler par exclusion :
import static pl.pojo.tester.api.FieldPredicate.include;
public class AnimalTest {
@Test
public void testPojoChatExclude() {
// Arrange
final Class<?> classUnderTest = Chat.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest, exclude("poids", "moustache", "petits")) //
.testing(EQUALS, HASH_CODE) //
.testing(CONSTRUCTOR) //
.areWellImplemented();
assertPojoMethodsFor(classUnderTest, exclude("name", "age")) //
.testing(SETTER) //
.areWellImplemented();
assertPojoMethodsFor(classUnderTest) //
.testing(GETTER) //
.areWellImplemented();
}Bien entendu, rien n'empêche de travailler à fois par inclusion et par exclusion, si cela vous semble plus simple.
Les auteurs de Pojo-Tester conseillent de privilégier les exclusions. Pourquoi ça ? Disons qu'on ajoute un attribut au bean mais qu'on oublie d'en tenir compte dans la méthode equals. Dans ce cas, la bibliothèque va s'en rendre compte si on travaille par exclusion. Au contraire, si on a oublié l'attribut dans equals, il est plus que probable qu'on l'aura aussi oublié dans inclusions, CQFD…
III-E. Dauphin Lombok : Dauphin▲
Si, comme votre serviteur, vous aimez la bibliothèque Lombok, vous serez content d'apprendre que Pojo-Tester saura gérer. Mais ajoutons d'abord Lombok à la liste de nos dépendances :
<project ...>
...
<dependencies>
...
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
</dependency>
</dependencies>Une introduction à Lombok est proposée dans un article intitulé « Simplifier le code de vos beans Java à l'aide de Commons Lang, Guava et Lombok ».
Ici on va simplement annoter le bean Dauphin avec @Data, qui génère toute la série des méthodes qu'on a déjà utilisées dans le reste de cet article.
import lombok.Data;
@Data
public class Dauphin {
private String name;
private int speed;Au niveau du test de Dauphin, on se contente de recopier le test classique qu'on avait écrit pour Chien :
import static pl.pojo.tester.api.FieldPredicate.include;
public class AnimalTest {
@Test
public void testPojoDauphin() {
// Arrange
final Class<?> classUnderTest = Dauphin.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.areWellImplemented();
}Et ça marche du premier coup, comme l'atteste le rapport Jacoco.
IV. Conclusion▲
Une fois n'est pas coutume, le contrat d'un article en cinq minutes est presque rempli. Il faut dire que le sujet semblait simple, du moins en apparence. Il est toutefois bien plus riche qu'on ne le pense au premier contact. La bibliothèque Pojo-Tester est ce genre d'outil qu'on ajoute à sa collection pour un besoin ponctuel et qui devient rapidement un incontournable, voire un irremplaçable.
Pojo-Tester se présente clairement comme un outil de test, mais la plupart des développeurs, y compris votre serviteur, vont initialement l'utiliser pour augmenter leur score de couverture. Il faut avouer qu'un score élevé fait toujours plaisir. Pour en obtenir un, de nombreux projets vont d'ailleurs tout simplement ignorer les POJO, qu'on considère généralement comme dénués de risque et/ou d'une importance secondaire. Même si c'est vrai au lancement du projet, cela devient une erreur avec le temps. En effet, qui n'a jamais été confronté à un bogue issu d'un mauvais copié-collé dans un getter/setter ou un attribut ajouté après coup au bean, mais oublié dans le equals/hashCode ? Ce genre de bogue est facile à corriger, mais hyperdifficile à identifier, ce qui fait perdre beaucoup de temps. La bibliothèque Pojo-Tester permet de s'en prémunir.
Pojo-Tester souffre néanmoins de quelques manques. On a déjà parlé de la méthode equals pour laquelle la couverture n'est pas complète. Gageons que cela sera amélioré avec le temps. Même ainsi, c'est une bibliothèque qu'on ne pourrait que conseiller d'avoir dans votre boîte à outils.
Vos retours et remarques nous aident à améliorer les publications de Developpez.com. N'hésitez donc pas à commenter cet article. Commentez ![]()
V. Remerciements▲
J'adresse mes remerciements aux auteurs de la bibliothèque Pojo-Tester. Merci de l'avoir créé et de la maintenir. Elles aident de nombreux développeurs à travers le monde.
Merci également à tous ceux qui ont contribué à la rédaction de cet article : Mickael Baron, jacques_jean et Winjerome.
VI. Annexes▲
VI-A. Liens▲
Projet dvp-article-pojo-tester sur GitHub : https://github.com/thierryler/dvp-article-pojo-tester
Pojo-Tester : http://www.pojo.pl/
Jacoco : http://www.eclemma.org/jacoco/
Lombok : https://projectlombok.org/
Mes autres articles : http://thierry-leriche-dessirier.developpez.com/
VI-B. Codes entiers▲
package com.dvp.tld.article.pojotester.domaine;
import java.util.Date;
import java.util.List;
public class Chien {
private String name;
private String race;
private double poids; // Poids en kg
private double taille; // Taille exprimee en metre
private Date dateNaissance;
private List<String> couleurs;
// private boolean mechant; // juste getter/setter
public Chien() {
// Rien
}
@Override
public String toString() {
return "Chien [name=" + name + ", race=" + race + ", poids=" + poids + ", taille=" + taille + ", dateNaissance="
+ dateNaissance + ", couleurs=" + couleurs + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((couleurs == null) ? 0 : couleurs.hashCode());
result = prime * result + ((dateNaissance == null) ? 0 : dateNaissance.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
long temp;
temp = Double.doubleToLongBits(poids);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((race == null) ? 0 : race.hashCode());
temp = Double.doubleToLongBits(taille);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Chien other = (Chien) obj;
if (couleurs == null) {
if (other.couleurs != null)
return false;
} else if (!couleurs.equals(other.couleurs))
return false;
if (dateNaissance == null) {
if (other.dateNaissance != null)
return false;
} else if (!dateNaissance.equals(other.dateNaissance))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Double.doubleToLongBits(poids) != Double.doubleToLongBits(other.poids))
return false;
if (race == null) {
if (other.race != null)
return false;
} else if (!race.equals(other.race))
return false;
if (Double.doubleToLongBits(taille) != Double.doubleToLongBits(other.taille))
return false;
return true;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRace() {
return race;
}
public void setRace(String race) {
this.race = race;
}
public double getPoids() {
return poids;
}
public void setPoids(double poids) {
this.poids = poids;
}
public double getTaille() {
return taille;
}
public void setTaille(double taille) {
this.taille = taille;
}
public Date getDateNaissance() {
return dateNaissance;
}
public void setDateNaissance(Date dateNaissance) {
this.dateNaissance = dateNaissance;
}
public List<String> getCouleurs() {
return couleurs;
}
public void setCouleurs(List<String> couleurs) {
this.couleurs = couleurs;
}
// public boolean isMechant() {
// return mechant;
// }
//
// public void setMechant(boolean mechant) {
// this.mechant = mechant;
// }
}package com.dvp.tld.article.pojotester.domaine;
public class Lapin {
// Attributs final
private final String name;
private final int age;
public Lapin(final String name, final int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Lapin other = (Lapin) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Lapin [name=" + name + ", age=" + age + "]";
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}package com.dvp.tld.article.pojotester.domaine;
import java.util.Arrays;
public class Chat {
// Attributs principaux (dans cons, hashcode et equals)
private final String name;
private final int age;
// Attributs en plus
private double poids;
private String moustache;
private String[] petits;
public Chat(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Chat [name=" + name + ", age=" + age + ", poids=" + poids + ", moustache=" + moustache + ", petits="
+ Arrays.toString(petits) + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Chat other = (Chat) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public double getPoids() {
return poids;
}
public void setPoids(double poids) {
this.poids = poids;
}
public String getMoustache() {
return moustache;
}
public void setMoustache(String moustache) {
this.moustache = moustache;
}
public String[] getPetits() {
return petits;
}
public void setPetits(String[] petits) {
this.petits = petits;
}
}package com.dvp.tld.article.pojotester.domaine;
import lombok.Data;
@Data
public class Dauphin {
private String name;
private int speed;
}package com.dvp.tld.article.pojotester.domaine;
import static pl.pojo.tester.api.FieldPredicate.exclude;
import static pl.pojo.tester.api.FieldPredicate.include;
import static pl.pojo.tester.api.assertion.Assertions.assertPojoMethodsFor;
import static pl.pojo.tester.api.assertion.Method.CONSTRUCTOR;
import static pl.pojo.tester.api.assertion.Method.EQUALS;
import static pl.pojo.tester.api.assertion.Method.GETTER;
import static pl.pojo.tester.api.assertion.Method.HASH_CODE;
import static pl.pojo.tester.api.assertion.Method.SETTER;
import static pl.pojo.tester.api.assertion.Method.TO_STRING;
import org.junit.Ignore;
import org.junit.Test;
public class AnimalTest {
@Test
public void testPojoChien() {
// Arrange
final Class<?> classUnderTest = Chien.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.areWellImplemented();
}
@Ignore
@Test
public void testPojoLapinFailed() {
// Arrange
final Class<?> classUnderTest = Lapin.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.areWellImplemented();
}
@Test
public void testPojoLapin() {
// Arrange
final Class<?> classUnderTest = Lapin.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.testing(GETTER) //
.testing(TO_STRING) //
.testing(EQUALS, HASH_CODE) //
.testing(CONSTRUCTOR) //
.areWellImplemented();
}
@Test
@Ignore
public void testPojoChatFailed() {
// Arrange
final Class<?> classUnderTest = Chat.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.testing(GETTER) //
.testing(TO_STRING) //
.testing(EQUALS, HASH_CODE) //
.testing(CONSTRUCTOR) //
.areWellImplemented();
}
@Test
public void testPojoChatInclude() {
// Arrange
final Class<?> classUnderTest = Chat.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest, include("name", "age")) //
.testing(EQUALS, HASH_CODE) //
.testing(CONSTRUCTOR) //
.areWellImplemented();
assertPojoMethodsFor(classUnderTest, include("poids", "moustache", "petits")) //
.testing(SETTER) //
.areWellImplemented();
assertPojoMethodsFor(classUnderTest) //
.testing(GETTER) //
.testing(TO_STRING) //
.areWellImplemented();
}
@Test
public void testPojoChatExclude() {
// Arrange
final Class<?> classUnderTest = Chat.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest, exclude("poids", "moustache", "petits")) //
.testing(EQUALS, HASH_CODE) //
.testing(CONSTRUCTOR) //
.areWellImplemented();
assertPojoMethodsFor(classUnderTest, exclude("name", "age")) //
.testing(SETTER) //
.areWellImplemented();
assertPojoMethodsFor(classUnderTest) //
.testing(GETTER) //
.areWellImplemented();
}
@Test
public void testPojoDauphin() {
// Arrange
final Class<?> classUnderTest = Dauphin.class;
// Act
// Assert
assertPojoMethodsFor(classUnderTest) //
.areWellImplemented();
}
}













