Skip to content

Instantly share code, notes, and snippets.

@AdrienHorgnies
Last active May 11, 2020 17:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AdrienHorgnies/4f21c6f392ee8f2797f25db73a7a61aa to your computer and use it in GitHub Desktop.
Save AdrienHorgnies/4f21c6f392ee8f2797f25db73a7a61aa to your computer and use it in GitHub Desktop.
A class to run dynamic tests

Dynamic tests

Dans le cadre du projet 1920_IUHDCB332

Usage

Les classe de test DynamicCompilationTest et DynamicOutputTest définissent deux variables qu'elle utilise pour trouver les scénarios de test:

  • TEST_SOURCE_FILES_DIR: indique où chercher les fichiers de code source SLIP
  • SOURCE_FILES_EXTENSIONS: indique quelles sont les extensions possibles des fichiers de code source SLIP

Tout fichier qui respectera ces deux conditions sera utiliser dans un scénario de test.

De plus, pour la classe DynamicCompilationTest, le nom du répertoire parent direct du fichier a de l'importance:

  • Si il s'appelle "ok" (en minuscule): le test unitaire s'attends à une compilation fructueuse
  • Si il s'appelle "ko" (en minuscule): le test unitaire s'attends à un échec de compilation
  • Sinon la suite de tests échoue et indique le fichier qui ne respecte pas les deux conventions ci-dessus

De même, pour la classe DynamicOutputTest, elle s'attend à trouver à côté de chaque fichier ".slip" un fichier ".nbc" qui correspondent. Ce fichier ".nbc" correspond au résultat attendu en sortie de la compilation du fichier ".slip". En cas de test raté, IntelliJ Idea permet de consulter un diff très compréhensible en cliquant sur "Voir les différences" dans la console du résultat des tests.

Par exemple, les trois fichiers "basic.slip", "basic.map" et "basic.nbc" correspondent respectivement à un fichier source dont on veut tester la compilation, un fichier map importé par le fichier source et un fichier contenant le résultat attendu de la compilation.

La classe va générer et exécuter un test unitaire pour chacun des fichiers trouvés et produire un rapport individuel à chaque test.

Dépendances

Ces tests requièrent JUnit 4.11 ou supérieur. J'utilise la librairie commons-io de Apache aussi.

Penser à ajouter ces dépendances dans votre pom.xml (example ci-dessous).

package be.unamur.info.b314.compiler.main;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import static org.hamcrest.Matchers.endsWith;
import static org.junit.Assert.assertThat;
@RunWith(Parameterized.class)
public class DynamicCompilationTest {
/**
* Will search recursively this directory for source files to test
*/
private static final String TEST_SOURCE_FILES_DIR = "src/test/resources/no_out";
/**
* Only files with one of these exceptions will be used
*/
private static final String[] SOURCE_FILES_EXTENSIONS = new String[]{"slip"};
private final File input;
private final boolean ok;
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
@Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
File resources = new File(TEST_SOURCE_FILES_DIR);
Collection<File> testFiles = FileUtils.listFiles(resources, SOURCE_FILES_EXTENSIONS, true);
Collection<Object[]> parameters = new ArrayList<>();
for (File testFile : testFiles) {
String result = testFile.getParentFile().getName();
if (result.equals("ok") || result.equals("ko")) {
String testName = resources.toURI().relativize(testFile.toURI()).getPath();
parameters.add(new Object[]{testName, testFile, result.equals("ok")});
} else {
throw new IllegalArgumentException(String.format("Folder containing test source should be 'ok' or 'ko' but is '%s' (%s)", result, testFile.getPath()));
}
}
return parameters;
}
/**
* Create object containing data for one single test unit
*
* @param testName name of the produced test, I must add this parameter or else I can't use it for the test name
* @param input file to compile
* @param ok result to expect
*/
public DynamicCompilationTest(String testName, File input, boolean ok) {
this.input = input;
this.ok = ok;
}
@Test
public void test() throws IOException {
launchCompilation(input, testFolder.newFile(), ok);
}
/**
* test the compilation of a file, expected success or failure depending the {@code ok} parameter
*
* @param in the source file to test
* @param out the produced compiled code
* @param ok if the source file should compile or not
* @throws IOException if reading/writing in and out file encounters a problem
*/
public static void launchCompilation(File in, File out, boolean ok) throws IOException {
ByteArrayOutputStream errContent = new ByteArrayOutputStream();
System.setErr(new PrintStream(errContent));
// Launch main method
Main.main(new String[]{"-i", in.getAbsolutePath(), "-o", out.getAbsolutePath()});
String expected;
if (ok) {
expected = String.format("OK%n"); // Using format to prevent EOL compatibility issues
} else {
expected = String.format("KO%n");
}
String assertMsg = String.format("'%s' must %s compilation", in.getName(), ok ? "succeed" : "fail");
assertThat(assertMsg, errContent.toString(), endsWith(expected)); // Check that the output ends with OK/KO
}
}
package be.unamur.info.b314.compiler.main;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public class DynamicOutputTest {
/**
* Will search recursively these directories for source files to test
*/
protected static String TEST_SOURCE_FILES_DIR = "src/test/resources/with_out";
/**
* Any file in {@value TEST_SOURCE_FILES_DIR} will be used to create a unit test
*/
private static final String[] SOURCE_FILES_EXTENSIONS = new String[]{"slip", "b314"};
private final File input;
private final File expectedOutput;
@Rule
public TemporaryFolder testFolder = new TemporaryFolder();
@Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
File resources = new File(TEST_SOURCE_FILES_DIR);
Collection<File> testFiles = FileUtils.listFiles(resources, SOURCE_FILES_EXTENSIONS, true);
Collection<Object[]> parameters = new ArrayList<>();
for (File testFile : testFiles) {
String testName = resources.toURI().relativize(testFile.toURI()).getPath();
File expectedOutput = new File(testFile.getPath().replace(".slip", ".nbc"));
if (!expectedOutput.exists()) {
throw new IllegalArgumentException(String.format("Could not find '%s' for '%s'.", expectedOutput.getPath(), testFile.getPath()));
}
parameters.add(new Object[]{testName, testFile, expectedOutput});
}
return parameters;
}
/**
* Create object containing data for one single test unit
* @param testName name of the produced test, I must add this parameter or else I can't use it for the test name
* @param input file to compile
* @param expectedOutput expected result of the compilation
*/
public DynamicOutputTest(String testName, File input, File expectedOutput) {
this.input = input;
this.expectedOutput = expectedOutput;
}
@Test
public void test() throws IOException {
File out = testFolder.newFile();
Main.main(new String[]{"-i", input.getAbsolutePath(), "-o", out.getAbsolutePath()});
assertEquals(FileUtils.readFileToString(expectedOutput, "UTF-8"), FileUtils.readFileToString(out, "UTF-8"));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<properties>
<junit.version>4.12</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
</project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment