Skip to content

Write tests

Tests should be written for every workflow/workflowstep, as well as every important class. They are written in Java, with JUnit 5.

In order to create a new test, the easiest way is to right click on the class to be tested, in Eclipse, and choose New > JUnit Test Case.

Basic example

  1. The first step is to write just enough code so that the tests compile:
    package eu.simstadt.workflows;
    
    import static org.junit.jupiter.api.Assertions.*;
    import org.junit.jupiter.api.Test;
    
    class VeryBasicTests
    {
        @Test
        void testStringConcatenation() {
            assertEquals("ab", f("a", "b"), "f should concatenate strings.");
        }
    
        private String f(String a, String b) {
            return null;
        }
    }
    
  2. Tests can be run with Run As > JUnit Test. The tests should fail. This step is really important, because otherwise, it's all too easy to write tests which don't test anything:
    org.opentest4j.AssertionFailedError: f should concatenate strings. ==> expected: <ab> but was: <null>
        at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
        at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)
        at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
        at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1135)
        at eu.simstadt.workflows.VeryBasicTests.testStringConcatenation(VeryBasicTests.java:10)
    ...
    
    Tests fail
  3. Without touching the testing methods, the tested code should be modified until the tests pass:
        private String f(String a, String b) {
    -       return null;
    +       return a + b;
        }
    
    Tests pass
  4. The tests should be run every time the corresponding code is modified. Continuous integration software, such as Jenkins, can help.

Complete example

Here is a complete example for a photovoltaic analysis in La Réunion.

It creates a workflow, runs it and checks if the results (temperature, irradiance, orientation on flat roof) are plausible for a location in the Southern Hemisphere.

package de.hftstuttgart.simstadtworkflows.casestudies;

import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import de.hftstuttgart.hierarchicworkflow.Project;
import de.hftstuttgart.hierarchicworkflow.WorkflowUtils;
import de.hftstuttgart.simstadtworkflows.energy.PhotovoltaicPotentialAnalysisWorkflowProvider;
import eu.simstadt.datamodel.SimStadtModel;
import eu.simstadt.irradiance.IrradianceTable;
import eu.simstadt.utils.TestsUtils;
import eu.simstadt.utils.UTF8WithBOM;
import eu.simstadt.weather.data.WeatherDataSet;
import eu.simstadt.workflows.CityGmlWorkflow;
import eu.simstadt.workflowsteps.IrradianceProcessor;
import eu.simstadt.workflowsteps.PhotovoltaicPotential;
import eu.simstadt.workflowsteps.WeatherProcessor;


class LaReunionPhotovoltaicPotentialTests
{
    @Test
    void testPhotovoltaicAndWeatherInSouthernHemisphere() throws Exception {
        String cityGMLBaseName = "Bldgtrial_3DLoD2_LaReunion_SteMarie_LaConvenance";
        Project repo = TestsUtils.testRepository();
        Project project = repo.projectNamed("LaReunion").get();
        CityGmlWorkflow<SimStadtModel> workflow = new PhotovoltaicPotentialAnalysisWorkflowProvider()
                .createWorkflow("PV Potential tests in LaReunion");
        try {
            project.addWorkflow(workflow);
            workflow.addCityGmlFileName(cityGMLBaseName + ".gml");
            PhotovoltaicPotential pvStep = TestsUtils.getWorkflowstep(workflow,
                    PhotovoltaicPotential.class);

            workflow.createDirectoriesAndSaveWorkflow();
            Path yearlyCSVPath = pvStep.getLocation().resolve(cityGMLBaseName +
                    "_inseldb_Hay_pv_potential.csv");
            SimStadtModel model = workflow.initAndRun().get(0);

            WeatherDataSet weather = model.getAttribute(WeatherProcessor.WEATHER_DATA_SET);
            double[] monthlyTemperatures = weather.getAmbientTemperature().getMonthlyAverages();
            double[] monthlyIrradiances = weather.getGlobalHorizontalIrradiance().getMonthlyAverages();
            IrradianceTable irradianceTable = model.getAttribute(IrradianceProcessor.IRRADIANCE_TABLE);

            assertTrue(
                    irradianceTable.getAverageIrradiance(0, 30) >
                    irradianceTable.getAverageIrradiance(180, 30) * 1.20,
                    "Modules to the North should get much more irradiance than to the South");

            assertTrue(monthlyIrradiances[0] > monthlyIrradiances[5] * 1.20,
                    "January should be summer");
            assertTrue(monthlyTemperatures[0] > monthlyTemperatures[5] + 5,
                    "January should be summer");

            String yearlyCSVContent = UTF8WithBOM.read(yearlyCSVPath);
            assertTrue(yearlyCSVContent.contains("Module azimuth on flat roof;0;°"),
                    "Modules should be oriented towards the north, in the southern hemisphere.");
        } finally {
            WorkflowUtils.deleteDirectory(workflow.getLocation());
        }
    }
}

Run Multiple Tests

  • From Eclipse, it is possible to right-click on a Project, and choose Run As > JUnit Test in order to automatically run every JUnit Test inside the project.
  • With Maven, simply running mvn clean package will automatically run every test that is needed for the current pom.xml.