Tuesday, June 25, 2019

Serveur mail portable : FakeSMTP

Afin de tester les envoies de mail en local, il existe FakeSMTP qui permet d'avoir un serveur mail cross platform pour les tests.

Pour le lancer, se placer dans le répertoire d'installation et lancer :

java -jar fakeSMTP-2.0.jar
Le port d'écoute est configurable (25 par défaut).

"Encourager" le lancement des tests avant un push

Sur un projet, nous avions des soucis concernant le nombre de build KO sur Jenkins à cause des tests non lancés sur notre back-end. Après avoir essayé le "on va faire attention", nous avons utilisé le script suivant au pre-push (hook Git).

Il se base sur la présence du fichier jacoco-tests.exec (pour SONAR) qui est généré lors du clean install. On vérifie que le fichier est présent et que sa dernière date de modification est inférieure à 20 minutes (pour ceux qui lançait bien le clean install avant de push, il n'y aura pas de changement dans leurs habitudes)
Pas la meilleure solution donc, but it works.


#!/bin/bash

# FilePaths to testing files generated by clean install
testsFile=./target/jacoco-tests.exec

run_clean_install () {
 echo "Running Maven clean install before push"
 mvn clean install
 if [ $? -ne 0 ]; then
   "Error while testing the code, cleaning project"
   rm "$testsFile"
   exit 1
 fi
}

if [ ! -f "$testsFile" ]; then
    echo "File $testsFile not found!"
 run_clean_install
else
 epochTwentyMinutes=1200
 currentEpoch=`/bin/date +%s`
 
 testsFileEpoch=`/bin/date -r "$testsFile" +%s`
 
 timePassedTestsFileEpoch=`expr $currentEpoch - $testsFileEpoch`
 
 if test "$timePassedTestsFileEpoch" -gt "$epochTwentyMinutes"; then
  echo "Obsoletes tests"
  run_clean_install
 fi 
fi

rm "$testsFile"
echo "Pre-push hook passed"

Script à placer dans /repertoire_projet/.git/hooks/pre-push

Création de macro "CLEAN CODE" avec Intellij

Le plugin SaveAction permet de faire des opérations lors de la sauvegarde ou via un raccourci.
Ayant eu des soucis avec le plugin et ne voulant pas faire d'opérations à chaque sauvegarde j'ai décidé de passer par une macro.

Dans le menu -> edit -> Macros, il est possible d'enregirster des combinaisons de raccourcis.

Par exemple, ajouter OptimizeImports, ReformatCode et SilentCodeCleanup.
Il suffit ensuite d'ajouter un raccourci sur la macro et TADA !!

Monday, June 24, 2019

Test unitaire des exceptions avec JUnit

Pour tester en détail une exception dans un test Junit, j'utilisais jusqu'ici expected qui teste uniquement qu'une exception du type est envoyé.

@Test(expected = 'MyException.class')
Pour Junit 4

L'utilisation de @Rule et ExpectedException permet de faire des tests plus poussés.
@Rule
public ExpectedException expectedEx = ExpectedException.none();

@Test
public void shouldThrowRuntimeExceptionWhenEmployeeIDisNull() throws Exception {
    expectedEx.expect(RuntimeException.class);
    expectedEx.expectMessage("Employee ID is null");
    // do something that should throw the exception...
}
Ou encore tester directement l'exception remontée.

@Test
public void shouldThrowMyExceptionWhenMyMockedServiceThrow() throws Exception {
    MyException myException = Mockito.mock(MyException.class);
    Mockito.when(myMockedService.myMockMethod()).thenThrow(myException);

    expectedEx.expect(Is.is(myException));
    myInjectedMockService.myInjectedMockMethod();
}

Cependant, dans les cas ou nous souhaitons tester qu'une méthode n'est pas appelée (à cause de l'exception) via verify, il faudra revenir à un try / catch classique.

Pour Junit 5

Pour activer JUnit 5 sur votre projet spring boot, suivez ce lien.

Avec JUnit 5, le test des exceptions devient simple et complet avec assertThrows

Voici un exemple:

@Test
public void shouldThrowMyExceptionWhenMyMockedServiceThrow() throws Exception {
    MyException myException = Mockito.mock(MyException.class);
    Mockito.when(myMockedService.myMockMethod()).thenThrow(myException);

    MyException thrownException = assertThrows(MyException.class, () -> myInjectedMockService.myInjectedMockMethod());

    assertEquals(myException, thrownException);
    verify(myOtherService, times(0)).otherMethod();
}

On a le meilleur des deux mondes. On récupère l'exception que l'on peut tester et on a toujours la main après pour faire d'autres assert / verify.