[JAVA] Introduisons le framework Spock et écrivons un test unitaire comme un test

introduction

Si vous essayez d'utiliser un framework de test appelé framework spock pour les tests unitaires en Java Je voudrais le présenter car c'était plus pratique que ce à quoi je m'attendais. Cliquez ici pour le site officiel → Spock Framework

Puisqu'il y a des endroits où le flux jusqu'à l'introduction est un peu difficile à comprendre, J'ai essayé d'écrire un article de la première introduction et d'écrire un test en utilisant spock. Je suis content si tu peux penser à Spock ouais.

Au fait, mon environnement est Ubuntu 18.04 LTS + eclipse, Bien sûr, vous pouvez utiliser spock dans un environnement Windows. Est-ce vrai?

Environnement d'écrivain

OS: Ubuntu 18.04 LTS IDE: eclipse

Création d'environnement

Introduit groovy

Introduction de groovy-eclipse

Cette fois, nous allons écrire le code de test avec groovy, donc nous allons introduire un plug-in pour gérer groovy dans eclipse.

Help > Install New Software > groovyのアドインを入れる1.PNG

Pour l'URL, reportez-vous à ce site (groovy-eclipse) et utilisez celui qui correspond à la version d'eclipse que vous utilisez. Vérifiez le paquet principal et terminez.

Création de test

Faire un projet

Cette fois, nous utiliserons gradle pour procéder rapidement. Accédez à n'importe quel répertoire dans lequel vous souhaitez placer le code source et exécutez gradle.

$ gradle init --type java-application --test-framework spock

c'est tout. Vous avez maintenant un projet qui utilise spock pour les tests unitaires. Facile!

Ajouter Spock à un projet existant

Si ce n'est pas nouveau, ajoutez la description au build.gradle existant (pom.xml pour maven).

build.gradle


plugins {
    id 'groovy'
}

repositories {
    jcenter()
}

dependencies {
    testImplementation 'org.codehaus.groovy:groovy-all:2.4.17'
    testImplementation 'org.spockframework:spock-core:1.0-groovy-2.4'
    testImplementation 'junit:junit:4.12'
}

Google Code Archive - Long-term storage for Google Code Project Hosting. Il est émietté, alors gardez celui en forme.

Spock version Groovy version JUnit version Grails version Spring version
0.5-groovy-1.6 1.6.1-1.6.x 4.7-4.x 1.2.0-1.2.x 2.5.0-3.x
0.5-groovy-1.7 1.7.0-1.7.x 4.7-4.x 1.3.0-1.3.x 2.5.0-3.x
0.6-groovy-1.7 1.7.0-1.7.x 4.7-4.x 1.3.0-1.3.x 2.5.0-3.x
0.6-groovy-1.8 1.8.1-1.8.x 4.7-4.x 2.0-2.x 2.5.0-3.x
0.7-groovy-1.8 1.8.1-1.8.x 4.7-4.x 2.0-2.x 2.5.0-3.x
0.7-groovy-2.0 2.0.0 -2.x.x 4.7-4.x 2.2-2.x 2.5.0-3.x
1.0-groovy-2.0 2.0.0 -2.2.x 4.7-4.x 2.2-2.x 2.5.0-4.x
1.0-groovy-2.3 2.3.0 -2.3.x 4.7-4.x 2.2-2.x 2.5.0-4.x
1.0-groovy-2.4 2.4.0 -2.x.x 4.7-4.x 2.2-2.x 2.5.0-4.x

Écrivons un test

Commencez à écrire comme un essai routier

Écrivons un test comme un essai. L'emplacement du test est src / test / groovy / [nom du package] /. L'extension est .groovy. Assurez-vous qu'il est dans le même package que la classe testée. Le nom de la classe de test est [Nom de la classe à tester] + Spec. En effet, il représente la spécification de la classe testée, même si cela s'appelle un test unitaire. C'est mon engagement, donc je pense que tout va bien.

Faites comme ça. image.png

Maintenant, implémentons une méthode qui calcule le montant TTC (8%) de la taxe à la consommation.

TaxCalculaterSpec.groovy


import spock.lang.Specification

class TaxCalculaterSpec extends Specification {
        def sut = new TaxCalculater()

        def "calculate:Calculez le montant TTC"() {
                expect:
                sut.calculate(100) == 108
        }
}                                                      

Soudain, j'ai écrit un test. Comme je l'ai dit plus tôt, il s'agit d'une spécification, donc le nom de la méthode de test est quelque chose qui représente la spécification. À ce stade, la construction ne réussira pas avant que le test ne réussisse, alors écrivez le code principal.

TaxCalculater.java


public class TaxCalculater {
    public int calculate(int value) {
        return 0;
    }
}

Eh bien, quand j'essaye de l'exécuter ...

Condition not satisfied:

sut.calculate(100) == 108
|   |              |
|   0              false

Oui, le test a brillamment échoué. C'est vrai, cela échoue car c'est une méthode qui renvoie 0.

Le point d'intérêt est la façon dont ce message apparaît. À la suite de l'exécution de la méthode, 0 a été renvoyé, donc la comparaison avec 108 est devenue fausse et le test a échoué. Vous pouvez voir en un coup d'œil. Cette facilité de compréhension est l'un des attraits de Spock.

Maintenant que nous avons confirmé que le test échoue, écrivons du code qui passera le test.

TaxCalculater.java


public class TaxCalculater {
    public int calculate(int value) {
        return 108;
    }
}

Le test a réussi. Je l'ai fait (je ne l'ai pas fait)

Levé triangulaire

Avec un seul test, vous ne savez pas si ce test est vraiment valide. Peut-être que cela renvoie simplement une valeur fixe. Par conséquent, il existe des variations de valeurs et de situations. Avec jUnit, vous pouvez augmenter le nombre d'appels de méthode dans de tels cas. C'est assez ennuyeux à cause du code en double, mais spock le rend un peu plus facile à lire.

TaxCalculaterSpec.groovy


class TaxCalculaterSpec extends Specification {
        def sut = new TaxCalculater()

        def "Calculez le montant TTC"() {
                expect:
                sut.calculate(value) == $result

                where:  
                value   |$result
                100     |108
                200     |216
        }
}

où! Quel mec! Soudain, un style d'écriture inconnu est sorti. C'est là une notation qui vous permet d'écrire une combinaison de valeurs qui s'écrit comme markdown. L'exemple ci-dessus montre que la méthode «calculer le montant TTC» est répétée pour le modèle. Puisqu'il existe deux modèles, cette méthode de test sera exécutée deux fois.

Si vous exécutez le test dans cet état, il échouera comme ceci.

Condition not satisfied:

sut.calculate(value) == $result
|   |         |      |  |
|   108       200    |  216
|                    false

216 est la valeur attendue, mais 108 est renvoyé, donc c'est vrai. C'est la mise en œuvre. On ne peut rien y faire.

Donc, je vais modifier l'implémentation.

TaxCalculater.java


public class TaxCalculater {

    public int calculate(int value) {
        return (int)(value * 1.08);
    }
}

Le test est maintenant réussi.

Lorsque des spécifications sont ajoutées

Ajoutons une spécification à la méthode de calcul du montant TTC. Ajoutez une spécification selon laquelle «les valeurs après la virgule décimale incluses dans le montant TTC sont arrondies au premier chiffre».

TaxCalculaterSpec.groovy


class TaxCalculaterSpec extends Specification {
        def sut = new TaxCalculater()

        def "Calculez le montant TTC"() {
                expect:
                sut.calculate(value) == $result

                where:
                value   |$result
                100     |108
                200     |216

                and: "Les valeurs inférieures à la virgule décimale incluses dans le montant TTC sont arrondies au premier chiffre."
                111     |120
        }
}

Ajouté au modèle where. 111 est 119,88 multiplié par 1,08, donc la valeur attendue doit être 120.

Condition not satisfied:

sut.calculate(value) == $result
|   |         |      |  |
|   119       111    |  120
|                    false

Il a été tronqué! !! (Je savais) Alors, mettons dans un processus d'arrondi.

TaxCalculater.java


public class TaxCalculater {
    public int calculate(int value) {
        return (int)(Math.round(value * 1.08));
    }
}

De cette façon, une fois les spécifications finalisées, nous ajouterons des modèles au test. Il est très facile de voir si vous écrivez les spécifications telles que les valeurs limites dans le test comme décrit ci-dessus. Et écrire un test vous donnera le courage de refactoriser.

TaxCalculater.java


public class TaxCalculater {
    private final static double taxRate = 1.08;

    public int calculate(int value) {
        return (int)(Math.round(value * taxRate));
    }
}

J'ai indiqué le taux d'imposition, mais le test réussit, il n'y a donc pas de problème. N'aimez-vous pas que le nom de la variable à valeur fixe soit camel case? Si tel est le cas, corrigeons-le et exécutons le test. C'est sûr si le test réussit.

exception

L'une des spécifications est qu'une exception se produit sous certaines conditions. Écrivons un test qui lève une exception.

TaxCalculaterSpec.groovy


	def "Une exception se produit lors du calcul du montant TTC à partir d'une valeur négative"() {
		when:
		sut.calculate(-1000)
		
		then:
		thrown(ApplicationException)
	}

C'est facile à comprendre! Faisons un test.

Expected exception of type 'org.omg.CORBA.portable.ApplicationException', but no exception was thrown
	at org.spockframework.lang.SpecInternals.checkExceptionThrown(SpecInternals.java:79)
	at org.spockframework.lang.SpecInternals.thrownImpl(SpecInternals.java:66)
	at spockSampleProject.TaxCalculaterSpec.Une exception se produit lors du calcul du montant TTC à partir d'une valeur négative(TaxCalculaterSpec.groovy:27)

Le test a échoué car ApplicationException était censée être levée mais ne l'a pas été.

TaxCalculater.java


public int calculate(int value) throws ApplicationException {
        if (value < 0) {
                throw new ApplicationException(null, null);
        }

        return (int) (Math.round(value * taxRate));
}

Si vous l'implémentez pour lever une exception si elle est négative et relancez le test, tout réussira. Je l'ai fait (je l'ai fait)

Rapports (mis à part)

Si vous décidez d'écrire la spécification du nom de méthode de la classe de test en japonais, le rapport sera beaucoup plus facile à lire. Si vous regardez cela, vous pouvez comprendre les spécifications. Personnellement, c'est beaucoup plus facile à lire que javadoc, donc je n'ai pas besoin d'écrire javadoc. Je pense écrire correctement un test unitaire. image.png

finalement

J'ai essayé la programmation pilotée par les tests en utilisant le framework spock, Qu'est-ce que tu penses.

Je serais heureux si vous pouviez exprimer la bonté de pouvoir rédiger les spécifications clairement et facilement. En plus du contenu introduit cette fois, il est assez puissant que vous puissiez écrire des tests moqueurs sans utiliser une bibliothèque fictive telle que mockit. Bien entendu, vous pouvez également tester les données en combinaison avec DbUnit. J'aimerais écrire ces articles bientôt.

Recommended Posts

Introduisons le framework Spock et écrivons un test unitaire comme un test
Introduire RSpec et écrire le code de test unitaire
Traitons le test unitaire comme la respiration (Apex trigger edition)
Lisez et écrivez comme java.nio
[rails] Faisons un test unitaire avec Rspec!