Tests
Three test suites are available, each started through its own class:
@Suite
@IncludeTags(Tags.UNIT)
@SelectPackages("de.hsrm.sls.subato")
public class UnitTestSuite {}
@Suite
@IncludeTags(Tags.INTEGRATION)
@ExcludeTags(Tags.EXTERNAL_DEPENDENCY)
@SelectPackages("de.hsrm.sls.subato")
public class IntegrationTestSuite {}
@Suite
@IncludeTags({Tags.INTEGRATION, Tags.EXTERNAL_DEPENDENCY})
@SelectPackages("de.hsrm.sls.subato")
public class ExternalIntegrationTestSuite {}
Test classes are tagged accordingly so that they run automatically as part of the matching suite.
Tags.EXTERNAL_DEPENDENCY marks classes that communicate with external systems and may therefore
need extra configuration to run. For example, TaskPoolRepositoryManagerTests is tagged with
Tags.EXTERNAL_DEPENDENCY because it depends on a VCS with valid Git credentials set through
environment variables for cloning (private) repositories.
Fixtures
src/test/resources/data.sql
The test environment has its own configuration (src/test/resources/application-testsuite.yml) that
overrides src/main/resources/application.yml and sets up the integration tests to run an instance of Subato against an H2 in-memory
database. The database is then initialized from src/test/resources/data.sql when the test runner starts.
A test that modifies the database must be annotated with @Transactional. Then, the change is rolled
back at the end of the test case, so the next one starts from the fresh state defined in
src/test/resources/data.sql. For example, UpdateCourseTest checks that updating a course through
the API works correctly. As this should cause a write to the database, the class is annotated with
@Transactional.
subato2-data
Beyond the database, some integration tests need tasks and solutions to be present on the file
system. These fixtures live under src/test/resources/testfiles/subato2-data and must match the
metadata in data.sql. Because running a test case can introduce changes to the subato2-data
directory, it should be reset before each test case as follows:
@BeforeAll
public static void beforeAll(@Autowired PrepareSubatoDataDir dataDirCleanup, @Autowired SubatoTmpDirCleanup tmpDirCleanup) {
dataDirCleanup.exec();
tmpDirCleanup.exec();
}
Testing Endpoints
Every endpoint should be tested to verify that authentication and authorization are enforced by
policies. As testing individual policies in isolation is often unnecessarily
cumbersome, each endpoint should instead get a test class with several integration tests. This
approach exercises all applicable policies together, ensuring that the endpoint is sufficiently
protected. These classes should also cover various edge cases to verify that the endpoint does what
it is supposed to. See UpdateCourseTest for an example.
To set the user context in a MockMvc integration test, the test method should be annotated with
@WithUserDetails, passing an username of an user that was declared in
src/test/resources/data.sql (e.g. U_STAFF_C1A). Usernames are encoded using the following schema:
U: a userSTAFF: thestaffroleC1A:Adminpermission in course 1
The declared users should be reused where possible to keep the test suite maintainable.