Indépendamment de JUnit, le code de configuration de l'appareil dans le code de test est Il a tendance à être long et réduit la lisibilité.
Dans cet article, nous nous concentrons sur la «valeur d'entrée» et la «valeur attendue» des éléments du dispositif de test. Je vais résumer la méthode de description de ces préparations proprement par paramétrage.
Les quatre étapes suivantes sont nécessaires pour le test de paramétrage de JUnit.
Si vous souhaitez effectuer un test paramétré, placez l'annotation RunWith dans la classe de test Spécifiez la classe org.junit.experimental.theories.Theories. Le lanceur de test Teories peut être utilisé avec le lanceur de test inclus.
@RunWith(Enclosed.class)
public class ParameterizedTest {
@RunWith(Theories.class)
public static class Pour les nombres{
}
@RunWith(Theories.class)
public static class Pour les chaînes{
}
@RunWith(Theories.class)
public static class Pour les nombres et les chaînes{
}
@RunWith(Theories.class)
public static class Pour les nombres et les nombres{
}
}
Pour les méthodes de test qui souhaitent utiliser des paramètres, Ajoutez une annotation Théorie au lieu de l'annotation Test.
Les méthodes de test avec l'annotation Theory peuvent déclarer des arguments arbitraires. Membres avec les annotations DataPoint et DataPoints décrites ci-dessous Défini dans l'argument en tant que paramètre.
@RunWith(Enclosed.class)
public class ParameterizedTest {
@RunWith(Theories.class)
public static class Pour les nombres{
@Theory
public void testCase(int num) throws Exception {
}
}
@RunWith(Theories.class)
public static class Pour les chaînes{
@Theory
public void testCase(String str) throws Exception {
}
}
@RunWith(Theories.class)
public static class Pour les nombres et les chaînes{
@Theory
public void testCase(int num, String str) throws Exception {
}
}
@RunWith(Theories.class)
public static class Pour les nombres et les nombres{
@Theory
public void testCase(int num1, int num2) throws Exception {
}
}
}
Dans le test paramétré à l'aide du lanceur de test Theories, Définissez les paramètres à l'aide de l'annotation DataPoint. Les paramètres sont définis dans des champs ou méthodes statiques et publics.
L'argument de la méthode avec l'annotation Theory est Parmi les valeurs avec l'annotation DataPoint, les paramètres qui correspondent au type Toutes les combinaisons sont passées en arguments.
@RunWith(Enclosed.class)
public class ParameterizedTest {
@RunWith(Theories.class)
public static class Pour les nombres{
@DataPoint
public static int INT_PARAM_1 = 3;
@DataPoint
public static int INT_PARAM_2 = 4;
@Theory
public void testCase(int num) throws Exception {
System.out.println("Valeur d'entrée:" + num);
}
}
@RunWith(Theories.class)
public static class Pour les chaînes{
@DataPoint
public static String STR_PARAM_1 = "Hello";
@DataPoint
public static String STR_PARAM_2 = "World";
@Theory
public void testCase(String str) throws Exception {
System.out.println("Valeur d'entrée:" + str);
}
}
@RunWith(Theories.class)
public static class Pour les nombres et les chaînes{
@DataPoint
public static int INT_PARAM_1 = 3;
@DataPoint
public static int INT_PARAM_2 = 4;
@DataPoint
public static String STR_PARAM_1 = "Hello";
@DataPoint
public static String STR_PARAM_2 = "World";
@Theory
public void testCase(int num, String str) throws Exception {
System.out.println("Valeur d'entrée:" + num + "、" + str);
}
}
@RunWith(Theories.class)
public static class Pour les nombres et les nombres{
@DataPoint
public static int INT_PARAM_1 = 3;
@DataPoint
public static int INT_PARAM_2 = 4;
@Theory
public void testCase(int num1, int num2) throws Exception {
System.out.println("Valeur d'entrée:" + num1 + "、" + num2);
}
}
}
Lorsque ParameterizedTest est exécuté, le contenu suivant est envoyé à la console.
~ Dans le cas d'une valeur numérique ~
Valeur d'entrée: 3
Valeur d'entrée: 4
~ Dans le cas d'une chaîne de caractères ~
Valeur d'entrée: Bonjour
Valeur d'entrée: Monde
~ Pour les nombres et les chaînes ~
Valeur d'entrée: 3, bonjour
Valeur d'entrée: 3, monde
Valeur d'entrée: 4, bonjour
Valeur d'entrée: 4, monde
~ Dans le cas de valeurs numériques et de valeurs numériques ~
Valeur d'entrée: 3, 3
Valeurs d'entrée: 3, 4
Valeurs d'entrée: 4, 3
Valeurs d'entrée: 4, 4
Si plus d'arguments sont passés à la méthode Theory En déclarant un DTO statique dans la classe de test, les arguments peuvent être combinés en un seul. Le DTO qui contient l'argument est appelé un objet fixture.
@RunWith(Theories.class)
public class ParameterizedTest {
@DataPoint
public static Fixture INT_PARAM_1 = new Fixture(1, 2, 3);
@DataPoint
public static Fixture INT_PARAM_2 = new Fixture(0, 2, 2);
@Theory
public void testCase(Fixture params) throws Exception {
assertThat(params.x + params.y, is(params.expected));
}
static class Fixture {
int x;
int y;
int expected;
Fixture(int x, int y, int expected) {
this.x = x;
this.y = y;
this.expected = expected;
}
}
}
L'annotation DataPoint ne pouvait définir qu'un seul paramètre, Avec l'annotation DataPoints, plusieurs paramètres peuvent être définis en un seul endroit.
@RunWith(Theories.class)
public class ParameterizedTest {
@DataPoints
public static Fixture[] INT_PARAMS = {
new Fixture(1, 2, 3),
new Fixture(0, 2, 2),
};
/*Définition à l'aide de l'annotation DataPoint
@DataPoint
public static Fixture INT_PARAM_1 = new Fixture(1, 2, 3);
@DataPoint
public static Fixture INT_PARAM_2 = new Fixture(0, 2, 2);
*/
@Theory
public void testCase(Fixture params) throws Exception {
assertThat(params.x + params.y, is(params.expected));
}
static class Fixture {
int x;
int y;
int expected;
Fixture(int x, int y, int expected) {
this.x = x;
this.y = y;
this.expected = expected;
}
}
}
params.yaml
!!seq [
!!test.ParameterizedTest$Fixture
{ x: 1, y: 2, expected: 3 },
!!test.ParameterizedTest$Fixture
{ x: 0, y: 2, expected: 2 },
]
@RunWith(Theories.class)
public class ParameterizedTest {
@DataPoints
public static Fixture[] INT_PARAMS = {
InputStream in = ParameterizedTest.class
.getResourceAsStream("params.yaml");
return ((List<Fixture>) new Yaml().load(in)).toArray(new Fixture[0]);
};
/*Définition à l'aide de l'annotation DataPoint
@DataPoint
public static Fixture INT_PARAM_1 = new Fixture(1, 2, 3);
@DataPoint
public static Fixture INT_PARAM_2 = new Fixture(0, 2, 2);
*/
@Theory
public void testCase(Fixture params) throws Exception {
assertThat(params.x + params.y, is(params.expected));
}
static class Fixture {
int x;
int y;
int expected;
Fixture(int x, int y, int expected) {
this.x = x;
this.y = y;
this.expected = expected;
}
}
}
Si vous spécifiez simplement les paramètres, toutes les combinaisons de tests seront exécutées. Dans un tel cas, certaines combinaisons peuvent ne pas correspondre aux valeurs attendues du test.
Par exemple, le test ci-dessus a vérifié si la valeur ajoutée était la même que la valeur attendue, S'il s'agit d'un test pour vérifier que la valeur ajoutée est égale Dans le cas de x = 1 et y = 2, la valeur d'entrée n'est pas celle attendue.
Dans ces cas, utilisez la classe Assume Seules les valeurs d'entrée prises en compte par le scénario de test peuvent être transmises.
Les méthodes fournies par la classe Assume incluent asumeTrue et assumeThat. Mettez en œuvre chacun comme suit.
assumeTrue(Expression conditionnelle);
assumeThat(Valeur d'entrée,méthode de mise en correspondance);
Quant au mouvement, lorsque le jugement de la méthode est faux dans les deux cas, En d'autres termes, si la valeur d'entrée n'est pas celle attendue, une AssumptionViolatedException sera générée. Aucun autre traitement n'est effectué. (Agit comme une clause de retour dans le code de test) Cette exception est traitée spécialement dans le lanceur de test, et même si l'exception est interceptée, le résultat du test réussira.
@RunWith(Theories.class)
public class ParameterizedTest {
@DataPoints
public static Fixture[] INT_PARAMS = {
new Fixture(1, 2, 3),
new Fixture(0, 2, 2),
};
@Theory
public void testCase(Fixture params) throws Exception {
//La valeur d'entrée est supposée être une valeur paire après l'addition.
//Valeur d'entrée inattendue(assumeTrue(false)Que devient)Dans le cas de, le traitement ultérieur n'est pas effectué
assumeTrue((params.x + params.y) % 2 == 0);
// x + y =Vérifiez qu'il est pair
assertThat((params.x + params.y) % 2 == 0 , is(true));
}
static class Fixture {
int x;
int y;
int expected;
Fixture(int x, int y, int expected) {
this.x = x;
this.y = y;
this.expected = expected;
}
}
}
L'exhaustivité, qui est un indice de qualité du test, dépend de la spécification des paramètres et de la classe Assume. Puisque c'est l'implémenteur qui fait le filtrage, juste parce que toutes les combinaisons sont testées Ce n'est pas un cas de test qui couvre les exigences et les spécifications. Par conséquent, en ce qui concerne la validité et l'exhaustivité des données de test, sous la direction de l'examinateur qui connaît la technique de test Il est nécessaire de prendre des mesures telles que la vérification.
Lors du test avec Theories test runner, le rapport s'affiche lorsque le test échoue L'information «Quel paramètre a échoué?» Est manquante. Par conséquent, dans le test paramétré, il est nécessaire de prendre des mesures en tenant compte de la facilité d'investigation lorsque le test échoue.
/*Exemple) Utilisez la méthode assertThat pour envoyer la valeur d'entrée au message au moment de l'échec*/
@Theory
public void testCase(Fixture params) throws Exception {
assumeTrue((params.x + params.y) % 2 == 0);
String failMsg = "Fail when x = " + params.x + ", y = " + params.y;
assertThat(failMsg, (params.x + params.y) % 2 == 0 , is(true));
}
Cet article a été rédigé en référence aux informations suivantes.
Recommended Posts