[JAVA] J'ai vérifié l'outil de création automatique de tests unitaires (version fin 2019)

J'ai vérifié l'outil de création automatique de tests unitaires (version fin 2019)

Bonjour. 2019 est presque terminée. Cet article est l'article du 25ème jour de Software Testing Advent Calendar 2019.

L'article de la veille a été écrit par mon collègue @ozhiro san, "Quel est votre but en faisant des tests automatisés? ](Https://qiita.com/ozhiro/items/5aa95c6360a8930df325). __être déplacé! __ En passant, j'ai examiné aujourd'hui l'état actuel de l'outil de création automatique de tests unitaires.

Pourquoi avez-vous décidé de le rechercher?

Les tests unitaires sont importants, n'est-ce pas? Le logiciel étant développé et modifié quotidiennement, le test unitaire est un outil de test qui garantit la qualité du logiciel développé. De plus, l'exécution des tests peut être automatisée, ce qui réduit l'effort de test.

Cependant, pour exécuter un test unitaire, il est nécessaire de développer un code de test, ce qui nécessite un certain effort de développement. Pour plus d'exhaustivité, cela peut prendre aussi longtemps que le développement du logiciel testé.

Dans un tel contexte, la situation est assez courante uniquement avec des tests manuels à la main sans créer de tests unitaires en raison d'une main-d'œuvre et d'un temps de développement insuffisants. (C'est différent maintenant, mais le projet du travail précédent et du travail précédent était comme ça.) De plus, j'ai déjà une énorme quantité de code source et je veux créer un test unitaire à partir de maintenant, mais par où puis-je commencer? Je pense qu'il y a de nombreuses situations où vous ne savez pas.

J'ai pensé là. Dans un tel monde où l'IA et la RPA (Robotic Process Automation) sont en plein essor, je pense que des outils qui analysent le code source et créent automatiquement des tests unitaires existent déjà dans ce monde. N'est-ce pas comme ça en 2020 ...? Quand.

Nous en 2020 (image): 2020年イメージ図

Découvrez les outils disponibles

Je vais immédiatement chercher sur Internet le type d'outils disponibles. La condition de recherche est "générer automatiquement un test unitaire", et comme je suis un ingénieur qui utilise principalement Java, j'ajoute également "Java" à la condition.

Étonnamment, il y a peu de résultats de recherche et d'anciens articles peuvent être vus ici et là, donc je me suis senti un peu mal à l'aise ... (´ ・ ω ・ `), mais j'en ai ramassé environ quatre bons.

Je ne savais pas comment l'utiliser simplement en regardant la vue d'ensemble, j'ai donc créé un code de test à partir du code source réel et l'ai évalué. Nous avons préparé les deux types de code source suivants.

  1. [Classe dont le traitement est fermé uniquement dans la classe et n'a que des méthodes sans état](https://github.com/policeman-kh/generate_test/blob/master/src/main/java/test/NumberUtils. Java)
  2. Classe de service Spring MVC

Je voulais ajouter des branches à la méthode 1 et ajouter le taux de couverture des tests à l'évaluation. 2 est une classe avec des instances DI (Dependency Injection). Je voudrais que vous remplaciez l'instance DI par une maquette de Mockito sur le code de test. J'ai un ressenti.

Le code source spécifique a été préparé sur GitHub en tant que projet avec le code de test créé. Il existe des liens vers GitHub à certains endroits, veuillez donc les consulter pour plus de détails.

Introduction et évaluation de l'outil

Maintenant, je voudrais présenter chaque outil et évaluer le code de test généré.

TestMe

Le code de test généré (partiel) est ci-dessous. L'instance DI est simulée à l'aide de Mockito. __Ça m'a l'air bien! __ Étant donné que le code de test n'est généré que selon le modèle, il n'y a pratiquement pas de taux de couverture et il est nécessaire de le développer séparément en fonction du code de test généré. Cependant, la vitesse de génération automatique n'est que de quelques secondes, et j'avais l'impression que ce n'était pas mal comparé à la création de code de test à partir de zéro.

Évaluation: Vitesse: ★★★★★ (plusieurs secondes) couverture: Personnalisation: ★★ (le cadre de test peut être sélectionné)

Cliquez ici pour le code de test et comment le générer

class ZipCodeServiceTest {
    @Mock
    ZipCodeApi zipCodeApi;
    @InjectMocks
    ZipCodeService zipCodeService;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    void testSearch() throws IOException {
        when(zipCodeApi.search(anyString())).thenReturn(null);

        List<ZipCodeData> result = zipCodeService.search("zipCode");
        Assertions.assertEquals(
                Arrays.<ZipCodeData>asList(
                        new ZipCodeData("zipcode", "prefcode", "address1", "address2", "address3", "kana1",
                                        "kana2", "kana3")), result);
    }
}

Squaretest

Est-ce presque la même chose que TestMe? C'est une impression, mais vous pouvez modifier le modèle sur l'écran de réglage. Je souhaite utiliser une autre bibliothèque telle que AssertJ ou Hamcrest pour l'assertion, donc cette zone est facile à utiliser. S'il ne s'agit pas d'une licence payante __, j'aimerais l'utiliser.

Évaluation: Vitesse: ★★★★★ (plusieurs secondes) couverture: Personnalisation: ★★★★ (Sélectionnez le cadre de test, modifiez le modèle)

Cliquez ici pour le code de test et comment le générer

class ZipCodeServiceTest {

    @Mock
    private ZipCodeApi mockZipCodeApi;

    private ZipCodeService zipCodeServiceUnderTest;

    @BeforeEach
    void setUp() {
        initMocks(this);
        zipCodeServiceUnderTest = new ZipCodeService(mockZipCodeApi);
    }

    @Test
    void testSearch() throws Exception {
        // Setup
        final List<ZipCodeData> expectedResult = Arrays.asList(
                new ZipCodeData("zipcode", "prefcode", "address1", "address2", "address3", "kana1", "kana2",
                                "kana3"));

        // Run the test
        final List<ZipCodeData> result = zipCodeServiceUnderTest.search("zipCode");

        // Verify the results
        assertEquals(expectedResult, result);
    }
}

EvoSuite

Le code de test créé à partir de 2 n'était pas assez bon, donc le code de test (partie) de 1 est décrit ci-dessous.

La génération du code de test prend 3 minutes. Cependant, cette zone peut être modifiée avec l'argument au moment de la génération. En regardant le taux de couverture du code de test ... __100% __ Incroyable! EvoSuiteカバレッジ率

Cependant, le code de test généré n'est pas lisible et je n'ai pas envie de le maintenir manuellement plus tard. De nombreuses annotations peu claires sont ajoutées, et le fait qu'il hérite de la classe de base d'EvoSuite est également un peu insatisfaisant. Pour simuler, jetez un œil à 1 code de test. Cependant, il n'a pas été réglé correctement. Ce problème indique qu'il peut être ajusté avec des arguments lors de la génération du code de test, mais une erreur se produit lors de l'exécution et cela finit par être une simulation. Il n'a pas été possible de générer du code de test. (Abandonné en chemin)

Cependant, le taux de couverture est très bon, il serait donc préférable de l'utiliser pour rechercher des bogues lors de la création d'une API sans état et publique. Je me sens comme.

Évaluation: Vitesse: ★★ (3 minutes) Couverture: ★★★★★ (100%!) Personnalisation: ★★ (Certains peuvent être spécifiés par des arguments lors de la génération du code de test)

Cliquez ici pour le code de test et comment le générer

@RunWith(EvoRunner.class) @EvoRunnerParameters(mockJVMNonDeterminism = true, useVFS = true, useVNET = true, resetStaticState = true, separateClassLoader = true, useJEE = true) 
public class NumberUtils_ESTest extends NumberUtils_ESTest_scaffolding {

  @Test(timeout = 4000)
  public void test00()  throws Throwable  {
      boolean boolean0 = NumberUtils.isOddNumberBetween1And50(50);
      assertFalse(boolean0);
  }
// omit other testcases.

Randoop

Ce que vous pouvez faire est presque identique à Evosuite. La couverture était également de 100%. __ Bien. __ Ce n'est pas facile à utiliser car il n'y a qu'une exécution en ligne de commande pour générer du code de test, mais je pense qu'il est bon que Jar d'exécution ne soit pas nécessaire pour exécuter le code de test généré.

Évaluation: Vitesse: ★★ (quelques minutes) Couverture: ★★★★★ (100%!) Personnalisation: ★★ (Certains peuvent être spécifiés par des arguments lors de la génération du code de test)

Cliquez ici pour le code de test et comment le générer

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class NumberUtilsTest {

    public static boolean debug = false;

    @Test
    public void test01() throws Throwable {
        if (debug)
            System.out.format("%n%s%n", "RegressionTest0.test01");
        // The following exception was thrown during execution in test generation
        try {
            boolean boolean1 = test.NumberUtils.isEvenNumberBetween1And10WithBadCode((-1));
            org.junit.Assert.fail("Expected exception of type java.lang.IllegalArgumentException; message: input should be between 1 and 10.");
        } catch (java.lang.IllegalArgumentException e) {
        // Expected exception.
        }
    }

Résumé

Jusqu'à présent, nous avons étudié et évalué les quatre outils de création automatique de tests unitaires. Pour être honnête, j'ai l'impression que c'est loin de l'image que j'attendais, mais je pense que c'était bon de connaître la situation actuelle.

Le code source, le code de test, l'ensemble de bibliothèques et HowTo ReadMe utilisés dans cette étude sont stockés sur le GitHub ci-dessous. Si vous souhaitez créer du code de test à l'aide de ces outils, nous vous serions reconnaissants de bien vouloir vous y référer.

Investigation of auto generation unit tests with Java

Eh bien, le long calendrier de l'Avent est terminé aujourd'hui. Merci à tous, lecteurs et écrivains! __ Bonne année!

Recommended Posts

J'ai vérifié l'outil de création automatique de tests unitaires (version fin 2019)
Création automatique du rapport de résultat du test unitaire Java
[Circle CI] J'étais accro au test automatique de Circle CI (rails + mysql) [Memo]
J'ai vérifié la partie de java.net.URL # getPath
J'ai vérifié le nombre de taxis avec Ruby
Essayez Progate Free Edition [Java I]
J'ai essayé de faire une version japonaise de la transmission automatique du courrier de Rails / devise
J'ai créé un outil pour afficher la différence du fichier CSV
J'étais accro au paramètre API version min23 de registerTorchCallback
[Édition Java] Histoire de la sérialisation
Vérifiez la version de Cent OS
J'ai lu la source de ArrayList que j'ai lu
J'ai lu la source d'Integer
J'ai lu la source de Long
Obtenez l'ID de la numérotation automatique
J'ai lu la source de Short
Importance de l'existence d'un test unitaire (auto-discussion)
J'ai lu la source de Byte
J'ai lu la source de String
J'obtiens des erreurs: l'utilisateur doit exister dans le test du modèle unitaire
Puisque le test unitaire de la PJ dont j'étais en charge était une photo d'enfer, je publierai mon propre guide (?)