Rationalisez les tests Java avec Spock

introduction

L'exemple de code de ce texte a été validé dans l'environnement suivant:


Qu'est-ce que Spock?

Spock est un cadre de test et de spécification pour les applications Java et Groovy. Comparé à d'autres outils, il dispose d'un langage de description de spécifications beau et expressif. https://spock-framework-reference-documentation-ja.readthedocs.io/ja/latest/introduction.html


Qu'est-ce qui est différent de JUnit?

La quantité de codage de test est extrêmement inférieure à JUnit! En d'autres termes, la quantité de codage est réduite, vous pouvez donc simplement augmenter l'efficacité des tests unitaires.

Alors, comment pouvez-vous réduire la quantité de codage de test?


Les tests peuvent être codés avec groovy

Spock écrit des tests avec groovy. Les caractéristiques du langage groovy permettent un codage plus léger que Java. Si la construction est progressive, les deux seront groovy, donc je pense que ce sera rapide à apprendre.

Groovy est un langage de programmation dynamique qui s'exécute sur la plate-forme Java. https://ja.wikipedia.org/wiki/Groovy

Pour ceux qui n'ont jamais utilisé groovy, le coût d'apprentissage peut être un fardeau. Cependant, puisque groovy peut écrire du code Java presque tel quel, si vous ne connaissez pas le pire code groovy, vous pouvez l'écrire en Java.

Dans quelle mesure le même test est-il codé dans JUnit et Spock (groovy)? Un exemple de code a été publié sur le github de Spock, voici donc un exemple de codage du même test dans JUnit.

JUnit


import static org.junit.Assert.assertEquals;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.h2.Driver;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class DatabaseDrivenTest {

	private static Connection con;

	@BeforeClass
	public static void setup() throws Exception {
		Driver.load();
		con = DriverManager.getConnection("jdbc:h2:mem:");

		Statement stmt = con.createStatement();
		stmt.execute("create table maxdata (id int primary key, a int, b int, c int)");
		stmt.execute("insert into maxdata values (1, 3, 7, 7), (2, 5, 4, 5), (3, 9, 9, 9)");
		stmt.close();
	}

	@Test
	public void testMaximumOfTwoNumbers() throws Exception {
		// Math.max(a, b) == c;
		Statement stmt = con.createStatement();
		ResultSet rs = stmt.executeQuery("select a, b, c from maxdata");
		rs.next();
		rs.getInt("a");
		assertEquals(Math.max(rs.getInt("a"), rs.getInt("b")), rs.getInt("c"));

		stmt.close();
	}

	@AfterClass
	public static void after() throws SQLException {
		con.close();
	}
}

Voici le code Spock. https://github.com/spockframework/spock-example/blob/master/src/test/groovy/DatabaseDrivenSpec.groovy

Vous constaterez que groovy est extrêmement simple.


Rationalisez les tests combinés avec les tests basés sur les données

Un autre mécanisme puissant est le test de démarrage des données. Les tests itératifs des combinaisons de paramètres et de résultats peuvent être facilement réalisés.

import spock.lang.*

@Unroll
class DataDrivenSpec extends Specification {
  def "minimum of #a and #b is #c"() {
    expect:
    Math.min(a, b) == c //Exécution des tests et vérification des résultats

    where:
    a | b || c    //Paramètre 1|Paramètre 2||résultat
    3 | 7 || 3
    5 | 4 || 4
    9 | 9 || 9
  }
}

Ce code est un test avec le contenu suivant: Le résultat de l'exécution de Math.min (a, b) avec a = 3 et b = 7 est 3 Le résultat de l'exécution de Math.min (a, b) avec a = 5 et b = 3 est 4 Le résultat de l'exécution de Math.min (a, b) avec a = 9 et b = 9 est 9

Si vous souhaitez augmenter la variation des paramètres et des résultats, vous pouvez imaginer ajouter un motif à où. Il s'agit d'un formulaire facile à convertir à partir de la table de modèles du test de combinaison créé dans Excel.


Rapport d'erreur

Si le test échoue, un rapport d'erreur sera imprimé sur la console. C'est plus gentil que la trace de pile d'erreur de Java.

Condition not satisfied:

validator.validate() == true
|         |          |
|         false      false
<Validator@5aa9e4eb>

	at ValidatorSpec.validate test(ValidatorSpec.groovy:40)


Facile à se moquer

Spock a également une fonction moqueuse.

Mock HttpServletRequest et réécrivez la valeur de retour de getRequestURI en "/some/path.html".

def request = Mock(HttpServletRequest)
request.getRequestURI() >> "/some/path.html"

Cependant, il existe diverses restrictions sur les moqueries, ce point sera donc décrit plus tard.


Méthode d'introduction

Il peut être installé avec gradle ou maven. Veuillez noter qu'il existe une dépendance de version avec groovy.

gradle


testCompile group: 'org.spockframework', name: 'spock-core', version: '1.3-groovy-2.5'
testCompile group: 'org.objenesis', name: 'objenesis', version: '3.0.1'
testCompile group: 'cglib', name: 'cglib', version: '3.2.10'

Maven


<dependency>
    <groupId>org.spockframework</groupId>
    <artifactId>spock-core</artifactId>
    <version>1.3-groovy-2.5</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.objenesis</groupId>
    <artifactId>objenesis</artifactId>
    <version>3.0.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.10</version>
</dependency>


exemple de configuration gradle

build.gradle


apply plugin: 'java'
apply plugin: 'groovy'

sourceSets {
	test {
		java {
			srcDir 'src/test/groovy'
		}
	}
}

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'org.spockframework', name: 'spock-core', version: '1.3-groovy-2.5'
    testCompile group: 'org.objenesis', name: 'objenesis', version: '3.0.1'
    testCompile group: 'cglib', name: 'cglib', version: '3.2.10'
}

Veuillez noter que le répertoire source doit être défini sur «rc / test / groovy».


Eclipse Plugins Pour l'utiliser avec Eclipse, vous devez installer le plug-in suivant. Veuillez installer à partir de Market Place.

Spock Plugin http://marketplace.eclipse.org/content/spock-plugin

Groovy Development Tools http://marketplace.eclipse.org/content/groovy-development-tools


Les bases de Spock

La forme de base du test ressemble à ceci.

class ValidatorSpec extends Specification {
    @Unroll
    def "Exemple de test param1=#param1 param2=#param2" () {
       setup: // 1.Prétraitement
            def target =nouvelle classe testée()
            def mockTarget = Mock(Classe dont vous voulez vous moquer)
            mockTarget.method() >>Valeur que vous souhaitez réécrire
            target.mockTarget = mockTarget //Attribuer une maquette à une variable membre de la classe testée
        expect: // 2.Exécution de la cible de test
            def returnObj = target.targetMethod(param1, param2)
        then: // 3.Vérification des résultats
            returnObj == result
            1 * mockTarget.method()
        where: // 4
.Combinaison de paramètres et de résultats
            | param1 | param2 || result
            | "a"    | 1      || "ok"
            | "b"    | 20     || "ng"
    }
}
  1. Lors du prétraitement, la classe cible de test est générée et la maquette est générée.
  2. Ici, exécutez la méthode cible de test de la classe cible de test.
  3. Vérifiez le résultat de l'exécution de la méthode de gestion des tests. Validation La validation est évaluée sur le booléen.
  4. Définissez une combinaison de paramètres et de résultats avec une épissure de tuyau. Le fait est que param1, param2 et result n'ont pas de déclaration de variable.

Type de bloc

Il existe les types de blocs suivants:

bloquer La description
expect Exécution des tests et vérification des résultats(when + then)
where Paramètres et résultats
when Exécutez la cible de test
then Vérification des résultats
setup(given) Pré-traitement
cleanup post-processus

Prend en charge les tests de code hérités en combinaison avec JMockit

Il existe des tests que Spock seul ne peut pas faire, tels que les constructeurs statiques, finaux et privés utilisés dans le code hérité. Si vous avez besoin de ces tests, nous vous recommandons d'utiliser JMockit.

 setup:
    new MockUp<LegacyUtil>() {
        @Mock
        public boolean check() {
            return true
        }
    }

Cas où l'effet de Spock ne peut être attendu

Une couverture de test à 100% est requise

Viser une couverture de test à 100% est très difficile, et atteindre 100% ne signifie pas une qualité élevée. Cependant, il existe en fait des projets de développement qui sont requis comme l'une des valeurs de l'indice de qualité. C'est difficile à réaliser avec spock seul, alors veuillez utiliser pleinement jMockit ou utiliser JUnit ensemble.

Classes difficiles à tester même avec JUnit

Le principe est de concevoir une classe facile à tester, mais je pense qu'il existe de nombreuses opportunités de rencontrer du code spaghetti sur le site de développement actuel. Veuillez refactoriser pour faciliter le test.

Site de référence

Spock http://spockframework.org

Document de référence du Spock Framework https://spock-framework-reference-documentation-ja.readthedocs.io/ja/latest/

Exemple de code Spock https://github.com/spockframework/spock-example

Recommended Posts

Rationalisez les tests Java avec Spock
Test avec com.google.testing.compile
Installez java avec Homebrew
Changer de siège avec Java
Installez Java avec Ansible
Téléchargement confortable avec JAVA
Changer java avec direnv
Téléchargement Java avec Ansible
Raclons avec Java! !!
Construire Java avec Wercker
Conversion Endian avec JAVA
(Java) BDD facile avec Spectrum?
Utiliser des couches Lambda avec Java
Créer un multi-projet Java avec Gradle
Premiers pas avec Java Collection
Configuration Java avec Spring MVC
Authentification de base avec Java 11 HttpClient
Expérimentons l'expansion en ligne Java
Exécuter un lot avec docker-compose avec Java batch
[Template] Connexion MySQL avec Java
Réécrire Java try-catch avec facultatif
Installez Java 7 avec Homebrew (cask)
[Java] Communication JSON avec jackson
Java pour jouer avec Function
Activer Java EE avec NetBeans 9
[Java] JavaConfig avec classe interne statique
Exploitons Excel avec Java! !!
Gestion des versions Java avec SDKMAN
Cryptage / décryptage RSA avec Java 8
Pagination de PDF avec Java + PDFBox.jar
[Java] Acquisition de contenu avec HttpCliient
Gestion des versions Java avec jenv
Dépannage avec Java Flight Recorder
Connectez-vous à DB avec Java
Connectez-vous à MySQL 8 avec Java
Erreur lors de la lecture avec java
Utilisation de Mapper avec Java (Spring)
Mémo d'étude Java 2 avec Progate
Test de l'API REST avec REST Assured
Premiers pas avec les bases de Java
Lorsque vous souhaitez implémenter des tests de bibliothèque Java avec Spock en multi-module avec Gradle dans Android Studio 3
Affichage saisonnier avec commutateur Java
Utiliser SpatiaLite avec Java / JDBC
Étudier Java avec Progate Note 1
Comparez Java 8 en option avec Swift
Analyse HTML (scraping) avec JAVA
Exécuter Java VM avec Web Assembly
Transition d'écran avec swing, java
Test unitaire Java avec Mockito
Une histoire sur la difficulté à aligner un cadre de test avec Java 6
[Java 8] Suppression en double (et vérification en double) avec Stream
Expression lambda Java apprise avec Comparator
Construire un projet Java avec Gradle
Installer Java avec Docker basé sur Ubuntu 16.04
Java pour apprendre avec les ramen [Partie 1]
Analyse morphologique en Java avec Kuromoji
Utiliser java avec MSYS et Cygwin
Traçage distribué avec OpenCensus et Java
BDD Java 100% pur avec JGiven (Introduction)
Test API automatique avec Selenium + REST-Assured