fbpx Comment faire des tests unitaires sur un smart contract en 1 jour sans se compliquer ? | Développeur Blockchain France

Comment faire des tests unitaires sur un smart contract en 1 jour sans se compliquer ?

Posté par Vincent Ton le octobre 31, 2019 dans Formation Développeur Blockchain
Card Image

Comment faire des tests unitaires sur un smart contract ?

Comment faire des tests unitaires sur un smart contract en un jour sans se compliquer

Aujourd’hui, peut-être que vous savez écrire des smart-contracts. Que vous comprenez Solidity. Et même que vous avez un projet de DAPP dans votre portfolio.

Et donc, vous postulez à un job de développeur Blockchain et vous montrez votre portfolio.

Malheureusement, l’entreprise ne vous a pas choisi.

« Mais pourquoi ? » : vous dites ça. C’est l’incompréhension la plus totale ! Vous avez la rage car au fond de vous, vous savez que vous êtes meilleurs que 99% des autres candidats.

Il se peut aussi que vous soyez déprimés, que vous voulez tout arrêter. Vous dites que « le job de développeur Blockchain n’est pas fait pour vous ». Vous voulez tout abandonner.

Pourtant, il suffit d’une seule chose. Si vous savez écrire un smart-contract, développez un DAPP et comprenez Solidity, il reste UNE SEULE CHOSE à savoir : réaliser des tests unitaires.

Les recruteurs aiment que vous soyez rigoureux. C’est pourquoi il est important de savoir faire des tests unitaires.

De plus, c’est écrit dans les offres d’emplois que le candidat doit savoir faire des tests unitaires. Oui, regardez l’image ci-dessous :

L’offre d’emploi s’adresse à un développeur Blockchain « senior » mais vous pouvez quand même postuler à ce type de job

Et c’est pourquoi j’ai décidé d’écrire un article sur les tests unitaires. À la fin de cet article, vous saurez comment faire des tests unitaires sur un smart-contract codé en Solidity.

Et vous augmentez vos chances d’être recrutés en tant que développeur Blockchain.

Pourquoi c’est important de savoir comment faire des tests unitaires sur un smart contract ?

Vous vous demandez pourquoi les recruteurs aiment bien que vous sachiez faire des tests unitaires. Eh bien, voici 4 raisons qui vont vous convaincre d’apprendre à faire des tests unitaires :

Raison 1 : Un smart-contract ne peut pas être modifié une fois déployé

Lorsqu’on déploie un smart-contract sur l’Ethereum, il ne sera plus possible de le modifier.

D’ailleurs, c’est pour ça qu’un développeur Blockchain utilise Ganache pour écrire les smart-contracts. Ganache permet de simuler une Blockchain dans votre ordinateur. Vous pouvez donc écrire les smart-contracts sans payer les frais de déploiements.

Pour modifier, il faut refaire un smart-contract et le redéployer dans le réseau Ethereum. Cela demande donc du temps. Et de l’argent car il faut dépenser de l’ether pour déployer dans la Blockchain Ethereum.

Raison 2 : Un hackeur peut détruire un smart-contract s’il y a des failles de sécurité

Qui dit smart-contract dit possibilité de gagner de l’argent. Surtout si c’est un smart-contract de type : ERC20. Si le smart-contract est mal codé, un hackeur peut facilement voler tous les jetons de votre smart-contract. Ou même prendre possession de votre smart-contract. Et mettre aux oubliettes votre projet Blockchain.

Par le passé, un projet ambitieux au nom de TheDAO qui avait réuni des millions d’euros a été piraté quelques heures après le déploiement. Provoquant la séparation (fork) de l’Ethereum en 2 chaînes : Ethereum et Ethereum Classic. D’ailleurs, c’est ce même évènement qui a permis aux développeurs de prendre conscience de l’importance de la sécurité sur les smart-contracts. Et donc de l’importance de faire des tests unitaires.

Un article sera rédigé sur la sécurité des smart-contracts. Si vous voulez en savoir plus sur la sécurité des smart-contract, vous pouvez aller sur ce site internet ludique. C’est https://capturetheether.com !

Raison 3 : Beaucoup de candidats ne font pas de tests unitaires.

Comme le métier de développeur Blockchain est récent, les personnes qui souhaitent apprendre ce métier se focalisent beaucoup sur l’apprentissage des langages informatiques dédiés à la Blockchain. Il y a par exemple Solidity ou Vyper pour Ethereum, Move pour Libra (la Blockchain de Facebook) ou C++ pour coder des smart-contracts pour la Blockchain EOS.

Cependant, ils oublient aux recruteurs de montrer qu’ils font des tests unitaires. Soit par flemme, soit parce qu’ils ne savent pas faire. Lorsqu’une entreprise ou un projet souhaitent déployer le smart-contract sur Ethereum, ils réalisent un audit avant. Et les résultats des audits sont souvent les mêmes : il y a des failles de sécurités car souvent, il n’y a aucun test unitaire réalisé sur les smart-contracts.

Réaliser les tests unitaires permet aux entreprises de perdre moins d’argent.

Raison 4 : Vous montrez au recruteur plusieurs qualités.

Faire des tests unitaires vous permet de marquer des points aux recruteurs.

Tout d’abord, le recruteur vous verra comme une personne rigoureuse. Car chaque fonction écrite dans le smart-contract est testée.

Ensuite, ils vous voient comme une personne qui a le sens du détail. Car vous savez tester les cas de succès et les cas d’échecs de votre smart-contract.

Enfin, ils vous voient comme quelqu’un d’efficace. En effet, si vous faites des tests unitaires sur les smart-contracts, vous verrez que vous allez être beaucoup plus rapide pour créer d’autres smart-contracts.

Maintenant que vous savez pourquoi apprendre à faire des tests unitaires, il est grand temps pour vous de découvrir comment faire !

Ainsi, vous allez faire 2 tests unitaires sur cet article.

Comment faire des tests unitaires sur un smart contract : 2 exemples

Commençons par le début.

Si vous avez lu cet article et appliqué ce qui est écrit, vous avez donc NodeJS, Ganache et truffle qui sont installés sur votre ordinateur. Et vous avez un dossier qui s’appelle tests/

Voyez le dossier tests/ ?

Mais vous pouvez très bien partir de zéro. Pour cela :
1 – Créez un nouveau dossier (par exemple : Test unitaire/)
2 – Avec le terminal, accédez au chemin de votre dossier avec la commande cd (cd Test unitaire)
3 – Une fois que vous êtes dans le bon dossier, faite la commande : $ truffle init

Vous aurez les fichiers et les fichiers qui vont s’ajouter, comme ceci :

Lorsqu’on part de zéro et qu’on fait la commande truffle init

Pour faire des tests unitaires, vous allez utiliser JavaScript et les outils suivants :
MochaJS dont la documentation se trouve sur le site https://mochajs.org/
ChaiJS dont la documentation se trouve sur le site https://www.chaijs.com/

MochaJS est une structure (ou framework) de test qui fonctionne sous NodeJS. ChaiJS est une librairie dédiée aux tests unitaires, c’est grâce à ChaiJS que vous pouvez utiliser les fonctions comme « Should », « Expect » ou « Assert ».

Nous allons tout d’abord tout d’abord vérifier que Truffle marche bien, avec la commande :

truffle test

Pour cela, nous allons premièrement créer un HelloWorld smart-contract et nous allons tester ce smart-contract.

Test unitaire 1 : Tester le HelloWorld smart-contract

Tout d’abord, on va vérifier que la commande truffle test fonctionne.

Pour cela, créez un nouveau fichier HelloWorld.sol dans le dossier contracts/.

Puis ajoutez ces lignes de codes :

pragma solidity ^0.5.0;

contract HelloWorld {
    function helloworld() public returns(string memory) {
        return("Hello World");
    }
}

Ensuite, créez un nouveau fichier 2_deploy_contracts.js dans le dossier migrations/.

Puis ajoutez ces lignes de codes :

const HelloWorld = artifacts.require("HelloWorld");

module.exports = function(deployer) {
  deployer.deploy(HelloWorld);
};

Vous pouvez faire la commande

truffle compile

pour voir si le smart-contract se compile. Pas la peine de faire $ truffle migrate pour déployer le smart-contract sur votre local (avec Ganache).

Ensuite, vous allez créer un fichier HelloWorld.test.js dans le dossier test/.

Et là, on va écrire le code.

1 – Importer le smart-contract

Vous allez importer le smart-contract en mettant le code suivant :

const HelloWorld = artifacts.require("./HelloWorld.sol");

2 – Structure globale du code

Voici la structure de base du code pour réaliser des tests unitaires.

const nomDuSmartContract = artifacts.require("./nomDuSmartContract.sol");

contract('nomDuSmartContract', (accounts) => {
    beforeEach(async () => {
        ...
    });

    it('Décrire le test', async () => {
        ...
    });
})

Tout d’abord, on importe le smart-contract. Ensuite, il y a la partie beforeEach puis la partie it.

Le bloc « beforeEach » permet d’executer les instructions avant chaque test qui arrive dans le bloc « it ».

Le bloc « it » permet de décrire les tests unitaires.

Le paramètre « accounts » permet d’ajouter les adresses. C’est idéal si on utilise Ganache.

3 – Le code du test unitaire pour HelloWorld.sol

Voici le code final pour tester le smart-contract HelloWorld.sol :

const HelloWorld = artifacts.require("./HelloWorld.sol");
let contractInstance;

contract('HelloWorld', (accounts) => {
    beforeEach(async () => {
        contractInstance = await HelloWorld.deployed()
    });

    it('must return the string Hello World with assert', async () => {
        const result = await contractInstance.helloworld() // helloworld() car //c'est la fonction qui vient du smart-contract
        assert.equal(result, "Hello World")
    });

    //it('must return the string Hello World with should', async () => {
    //    const result = await contractInstance.helloworld()
    //    result.should.not.equal(1)
    //});

    it('must return the string Hello World with expect', async () => {
        const result = await contractInstance.helloworld()
        expect(result).to.equal("Hello World")
        expect(result).to.be.a('string')
    });
})

Avec la librairie Chai, il y a 3 manières de décrire les tests : avec la fonction assert(), should() ou expect().

Dans le bloc it, j’ai utilisé helloworld() car cette fonction provient du smart-contract HelloWorld.sol.

Ensuite, une fois que vous avez ajouté le code, faites la commande ci-dessous dans le terminal :

truffle test
Voici ce que doit retourner truffle test

Comme vous le voyez dans le code, j’ai mis en commentaire le test avec should. Car le test ne fonctionnait pas (avec le message d’erreur dans l’image ci-dessus).

L’avantage, c’est que si une des tests ne fonctionne pas, il reste toujours 2 tests.

Après, si truffle test ne fonctionne pas, il faut modifier le code dans truffle-config.js en ajoutant ceci :

module.exports = {
  networks: {
      development: {
          host: "127.0.0.1",
          port: 7545,
          network_id: "*"
      }
  }
};

N’oubliez pas d’ouvrir l’application Ganache.

Test unitaire 2 : Tester le smart-contract Election.sol

Vous allez utiliser le smart-contract dont le code est écrit dans cet article.

Ensuite, vous allez créer un fichier Election.test.js dans le dossier test/

Voici les fonctions qui ont été utilisées dans Election.sol :

  • rechercherCandidat()
  • voterCandidat()
  • voirResultat() (qui est pratiquement la même chose que rechercherCandidat())

Tout d’abord, nous allons importer le smart-contract dans le fichier Election.test.js en ajoutant ceci :

 {
  beforeEach(async () => {
    contractInstance = await Election.deployed()
  });

// Code à ajouter en dessous

});

Remarquez qu’il y a 3 électeurs : [electeur1, electeur2, electeur3]. Les 3 électeurs correspondent en réalité à 3 adresses différentes, les 3 adresses de Ganache.

Ensuite, nous allons tester s’il y a bien 2 candidats : Pain au chocolat et Chocolatine. Pour cela, vous pouvez ajouter ce code suivant dans « contract » :

 {
    const result = await contractInstance.nombreDeCandidat();
    assert.equal(result, 2, "have good number of Candidat")
});

it("la fonction rechercherCandidat donne de bonnes résultats", async () => {
    const result = await contractInstance.rechercherCandidat(1);
    assert.equal(result[0], "Pain au chocolat", "le nom du premier candidat est Pain au Chocolat");
    assert.equal(result[1], "0", "le nombre de vote du 1er candidat est de zéro")
    const result1 = await contractInstance.rechercherCandidat(2);
    assert.equal(result1[0], "Chocolatine", "le nom du deuxième candidat est Chocolatine");
    assert.equal(result1[1], "0", "le nombre de vote du 2e candidat est de zéro")  
});

Ensuite, nous allons tester la fonction voterCandidat().

Nous allons tout d’abord tester si la fonction voterCandidat() marche. Puis nous allons tester les deux cas où la fonction voterCandidat() retourne un message d’erreur. Les deux cas sont :

  • Lorsqu’on vote pour un candidat inexistant (par exemple : voterCandidat(99))
  • Lorsqu’un électeur tente de tricher en votant 2 fois.

Voici le code à mettre :

describe('tester la fonction voterCandidat', () => {
    before(async () => {
      const candidatNumero = 1;
      aVoté = await contractInstance.voterCandidat(candidatNumero, {from: electeur1});
    });

    it('Pain au chocolat a le nombre de vote égale à 1', async () => {
      const result = await contractInstance.rechercherCandidat(1);
      assert.equal(result[0], "Pain au chocolat", "le nom du premier candidat est Pain au Chocolat");
      assert.equal(result[1], "1", "le nombre de vote du 1er candidat est de 1 !")
    });

    it('Retourne une erreur pour des candidats inexistant', () => {
      return contractInstance.voterCandidat(99, { from: electeur2 })
      .then(assert.fail).catch(function(error) {
        assert(error.message.indexOf('revert') >= 0, "error message must contain revert");
      });
    });

    it('Retourne une erreur quand un electeur tente de voter 2 fois', function() {
      const candidatNumero = 2;
      contractInstance.voterCandidat(candidatNumero, { from: electeur3 });
      // Try to vote again
      return contractInstance.voterCandidat(candidatNumero, { from: electeur3 })
      .then(assert.fail).catch(function(error) {
      assert(error.message.indexOf('revert') >= 0, "error message must contain revert");
      });
    });
  });

Avec le bloc « describe », il est possible de regrouper plusieurs tests.

Remarquez que j’ai mis « before » au lieu de « beforeEach ». La fonction « beforeEach » permet d’exécuter l’instruction avant CHAQUE test (ou avant chaque « it »). La fonction « before » permet seulement d’exécuter l’instruction UNE SEULE FOIS avant la partie test.

Voici ce que donne une fois que les tests ont été faits :

Les tests réalisés avec succès après truffle test

Conclusion :

Au début de cet article, vous vous demandez comment faire des tests unitaires sur un smart-contract. En utilisant JavaScript, le framework MochaJS et la bibliothèque ChaiJS, vous êtes en mesure de faire des tests unitaires sur vos propres smart-contracts.

N’oubliez pas que les recruteurs aiment que vous sachiez faire des tests unitaires. Et ceci est même très important dans le cadre d’un projet Blockchain.

Peut-être que vous n’aimez pas faire des tests unitaires car cela peut prendre du temps. Mais si vous ne le faites pas, vous ne pourriez pas savoir si votre smart-contract possède des failles de sécurités majeures.

Et si vous arriviez à faire les tests unitaires sur le smart-contract HelloWorld, alors vous seriez 99% plus avancés que les autres candidats qui souhaitent devenir développeur Blockchain.

Réservez une session offerte de 45 minutes avec moi si vous voulez devenir développeur Blockchain.

Laisser un commentaire

Your email address will not be published. All fields are required.