Improve test data creation (#112)
Currently there is only one class used to add test data; [`DataInitializer`](b9f7dd5a49/core/src/main/java/se/su/dsv/scipro/DataInitializer.java
). That class is already very large and causes a lot of merge conflicts when multiple changes are in the pipeline as noted by #109.
This change makes it possible to have multiple classes adding test data so that each change adds its own class and thus there are no conflicts. It also has the benefit of making each class smaller and more self-contained for testing a specific feature.
Some additional infrastructure was added in the form of the `BaseData` and `Factory` (naming improvements notwithstanding) interfaces to help each class add its own test data and re-use common data.
Finally all test data related classes have been moved to their own module so they can be properly excluded when building for production but are included by default while developing.
Fixes #109
## Future work
* Add a mechanism to work with date and time.
Many processes (and therefore service method implementations) rely on the time between certain events. For example a final seminar must be scheduled a set amount of days in advance. In the ideal world, the test data is populated using these service methods to more accurately represent an achievable real world state. Therefore there must be a way to manipulate time when adding test data.
* Add more methods to the `Factory` interface as we discover more common steps that many populators must take.
* Add more base data available through the `BaseData` interface as we discover more common data that many populators need
Care must be taken that this data is final and useful in its base state since populators will rely on that state.
Co-authored-by: Nico Athanassiadis <nico@dsv.su.se>
Reviewed-on: #112
Reviewed-by: Nico Athanassiadis <nico@dsv.su.se>
Co-authored-by: Andreas Svanberg <andreass@dsv.su.se>
Co-committed-by: Andreas Svanberg <andreass@dsv.su.se>
This commit is contained in:
parent
7f9e72484a
commit
a76b317b1c
.gitignoreDockerfile
core/src/main/java/se/su/dsv/scipro
pom.xmltest-data
pom.xml
src/main
java/se/su/dsv/scipro/testdata
BaseData.javaDataInitializer.javaFactory.javaTestDataConfiguration.javaTestDataPopulator.javapackage-info.java
populators
resources/META-INF/services
war
1
.gitignore
vendored
1
.gitignore
vendored
@ -25,4 +25,5 @@ fitnesse/target/
|
||||
daisy-integration/target/
|
||||
war/target/
|
||||
api/target/
|
||||
test-data/target/
|
||||
node_modules/
|
||||
|
@ -12,12 +12,14 @@ COPY core/pom.xml core/pom.xml
|
||||
COPY view/pom.xml view/pom.xml
|
||||
COPY war/pom.xml war/pom.xml
|
||||
COPY daisy-integration/pom.xml daisy-integration/pom.xml
|
||||
COPY test-data/pom.xml test-data/pom.xml
|
||||
|
||||
COPY api/src/ api/src/
|
||||
COPY core/src/ core/src/
|
||||
COPY view/src/ view/src/
|
||||
COPY war/src/ war/src/
|
||||
COPY daisy-integration/src/ daisy-integration/src/
|
||||
COPY test-data/src/ test-data/src/
|
||||
|
||||
RUN ./mvnw package \
|
||||
--define skipTests \
|
||||
|
@ -1017,11 +1017,6 @@ public class CoreConfig {
|
||||
);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataInitializer dataInitializer() {
|
||||
return new DataInitializer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FinalSeminarActivityHandler finalSeminarActivityHandler(
|
||||
ActivityPlanFacade activityPlanFacade,
|
||||
|
1
pom.xml
1
pom.xml
@ -15,6 +15,7 @@
|
||||
<module>daisy-integration</module>
|
||||
<module>war</module>
|
||||
<module>api</module>
|
||||
<module>test-data</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
20
test-data/pom.xml
Normal file
20
test-data/pom.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>se.su.dsv.scipro</groupId>
|
||||
<artifactId>SciPro</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>test-data</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>se.su.dsv.scipro</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
19
test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java
vendored
Normal file
19
test-data/src/main/java/se/su/dsv/scipro/testdata/BaseData.java
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
package se.su.dsv.scipro.testdata;
|
||||
|
||||
import se.su.dsv.scipro.system.ProjectType;
|
||||
|
||||
/// All the base test data that can be re-used in different test cases.
|
||||
///
|
||||
/// **Do not modify any of this data.** There are many
|
||||
/// [TestDataPopulator]s that rely on this data to be in a specific state.
|
||||
///
|
||||
/// In addition to the data that is available here there is also much additional
|
||||
/// data that has been created;
|
||||
///
|
||||
/// - A grading report template for each [ProjectType]
|
||||
///
|
||||
public interface BaseData {
|
||||
ProjectType bachelor();
|
||||
ProjectType magister();
|
||||
ProjectType master();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package se.su.dsv.scipro;
|
||||
package se.su.dsv.scipro.testdata;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Provider;
|
||||
@ -34,13 +34,16 @@ import se.su.dsv.scipro.security.auth.roles.Roles;
|
||||
import se.su.dsv.scipro.system.*;
|
||||
import se.su.dsv.scipro.util.Pair;
|
||||
|
||||
public class DataInitializer implements Lifecycle {
|
||||
public class DataInitializer implements Lifecycle, BaseData, Factory {
|
||||
|
||||
public static final int APPLICATION_PERIOD_START_MINUS_DAYS = 1;
|
||||
public static final int APPLICATION_PERIOD_END_PLUS_DAYS = 3;
|
||||
public static final int APPLICATION_PERIOD_COURSE_START_PLUS_DAYS = 5;
|
||||
public static final long RESEARCH_AREA_ID = 12L;
|
||||
|
||||
@Inject
|
||||
private Collection<TestDataPopulator> testDataPopulators = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
private UserService userService;
|
||||
|
||||
@ -120,6 +123,9 @@ public class DataInitializer implements Lifecycle {
|
||||
createTarget();
|
||||
createStudentIdea();
|
||||
createRoughDraftApproval();
|
||||
for (TestDataPopulator testDataPopulator : testDataPopulators) {
|
||||
testDataPopulator.populate(this, this);
|
||||
}
|
||||
}
|
||||
if (profile.getCurrentProfile() == Profiles.DEV && noAdminUser()) {
|
||||
createAdmin();
|
||||
@ -243,13 +249,18 @@ public class DataInitializer implements Lifecycle {
|
||||
sofia_student = createStudent("Sofia", 17);
|
||||
}
|
||||
|
||||
private User createStudent(String firstName, int identifier) {
|
||||
private User createStudent(String firstName) {
|
||||
User user = createUser(firstName, STUDENT_LAST);
|
||||
user.setIdentifier(identifier);
|
||||
createBeta(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
private User createStudent(String firstName, int identifier) {
|
||||
User user = createStudent(firstName);
|
||||
user.setIdentifier(identifier);
|
||||
return user;
|
||||
}
|
||||
|
||||
private User createEmployee(String firstName) {
|
||||
User user = createUser(firstName, EMPLOYEE_LAST);
|
||||
Unit u = createUnit();
|
||||
@ -2087,6 +2098,36 @@ public class DataInitializer implements Lifecycle {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectType bachelor() {
|
||||
return bachelorClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectType magister() {
|
||||
return magisterClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectType master() {
|
||||
return masterClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User createAuthor(String firstName) {
|
||||
return createStudent(firstName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User createSupervisor(String firstName) {
|
||||
return createEmployee(firstName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User createReviewer(String firstName) {
|
||||
return createEmployee(firstName);
|
||||
}
|
||||
|
||||
private static final class SimpleTextFile implements FileUpload {
|
||||
|
||||
private final User uploader;
|
46
test-data/src/main/java/se/su/dsv/scipro/testdata/Factory.java
vendored
Normal file
46
test-data/src/main/java/se/su/dsv/scipro/testdata/Factory.java
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
package se.su.dsv.scipro.testdata;
|
||||
|
||||
import se.su.dsv.scipro.security.auth.roles.Roles;
|
||||
import se.su.dsv.scipro.system.User;
|
||||
|
||||
/**
|
||||
* A factory to help with repetitive tasks when populating test data.
|
||||
*/
|
||||
public interface Factory {
|
||||
/**
|
||||
* Creates a user with the given first name and last name "Student".
|
||||
* The user is given the role {@link Roles#AUTHOR}.
|
||||
* <p>
|
||||
* A username is created of the form {@code <first_name>@example.com} that
|
||||
* can be used to log in.
|
||||
*/
|
||||
User createAuthor(String firstName);
|
||||
|
||||
/**
|
||||
* Creates a user with the given first name and last name "Employee".
|
||||
* <p>
|
||||
* The user is given the role {@link Roles#SUPERVISOR}, {@link Roles#REVIEWER},
|
||||
* and {@link Roles#EXAMINER}.
|
||||
* <p>
|
||||
* The user gets a default research area, unit, and language. It is also
|
||||
* marked as {@link User#setActiveAsSupervisor(boolean) an active supervisor}.
|
||||
* <p>
|
||||
* A username is created of the form {@code <first_name>@example.com} that
|
||||
* can be used to log in.
|
||||
*/
|
||||
User createSupervisor(String firstName);
|
||||
|
||||
/**
|
||||
* Creates a user with the given first name and last name "Employee".
|
||||
* <p>
|
||||
* The user is given the role {@link Roles#SUPERVISOR}, {@link Roles#REVIEWER},
|
||||
* and {@link Roles#EXAMINER}.
|
||||
* <p>
|
||||
* The user gets a default research area, unit, and language. It is also
|
||||
* marked as {@link User#setActiveAsSupervisor(boolean) an active supervisor}.
|
||||
* <p>
|
||||
* A username is created of the form {@code <first_name>@example.com} that
|
||||
* can be used to log in.
|
||||
*/
|
||||
User createReviewer(String firstName);
|
||||
}
|
16
test-data/src/main/java/se/su/dsv/scipro/testdata/TestDataConfiguration.java
vendored
Normal file
16
test-data/src/main/java/se/su/dsv/scipro/testdata/TestDataConfiguration.java
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
package se.su.dsv.scipro.testdata;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import se.su.dsv.scipro.war.PluginConfiguration;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ComponentScan(basePackages = "se.su.dsv.scipro.testdata.populators")
|
||||
public class TestDataConfiguration implements PluginConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataInitializer dataInitializer() {
|
||||
return new DataInitializer();
|
||||
}
|
||||
}
|
11
test-data/src/main/java/se/su/dsv/scipro/testdata/TestDataPopulator.java
vendored
Normal file
11
test-data/src/main/java/se/su/dsv/scipro/testdata/TestDataPopulator.java
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
package se.su.dsv.scipro.testdata;
|
||||
|
||||
public interface TestDataPopulator {
|
||||
/**
|
||||
* Add test data to the system to help with testing a specific feature.
|
||||
*
|
||||
* @param baseData the base data already populated
|
||||
* @param factory helper object to make repetitive tasks easier (such as creating users)
|
||||
*/
|
||||
void populate(BaseData baseData, Factory factory);
|
||||
}
|
8
test-data/src/main/java/se/su/dsv/scipro/testdata/package-info.java
vendored
Normal file
8
test-data/src/main/java/se/su/dsv/scipro/testdata/package-info.java
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* This package contains the infrastructure that is used when generating test data for the application. To add new test
|
||||
* data to the system, add a new class to the {@link se.su.dsv.scipro.testdata.populators} package that implements the
|
||||
* {@link se.su.dsv.scipro.testdata.TestDataPopulator} interface and annotate it with
|
||||
* {@link org.springframework.stereotype.Service @Service}. Inject dependencies as needed using
|
||||
* {@link jakarta.inject.Inject @Inject}.
|
||||
*/
|
||||
package se.su.dsv.scipro.testdata;
|
13
test-data/src/main/java/se/su/dsv/scipro/testdata/populators/package-info.java
vendored
Normal file
13
test-data/src/main/java/se/su/dsv/scipro/testdata/populators/package-info.java
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Contains classes that populate the database with test data.
|
||||
* <p>
|
||||
* Prefer to use methods on the various services to create data, rather than directly interacting with the database
|
||||
* using an {@link jakarta.persistence.EntityManager}. This is to make sure all business rules are enforced and that
|
||||
* any additional logic is executed such as sending notifications or calculating statistics.
|
||||
*
|
||||
* @see se.su.dsv.scipro.testdata how to add new populators
|
||||
* @see se.su.dsv.scipro.testdata.TestDataPopulator
|
||||
* @see se.su.dsv.scipro.testdata.BaseData
|
||||
* @see se.su.dsv.scipro.testdata.Factory
|
||||
*/
|
||||
package se.su.dsv.scipro.testdata.populators;
|
1
test-data/src/main/resources/META-INF/services/se.su.dsv.scipro.war.PluginConfiguration
Normal file
1
test-data/src/main/resources/META-INF/services/se.su.dsv.scipro.war.PluginConfiguration
Normal file
@ -0,0 +1 @@
|
||||
se.su.dsv.scipro.testdata.TestDataConfiguration
|
13
war/pom.xml
13
war/pom.xml
@ -140,5 +140,18 @@
|
||||
<spring.profile.active>branch</spring.profile.active>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>DEV</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>se.su.dsv.scipro</groupId>
|
||||
<artifactId>test-data</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
Loading…
x
Reference in New Issue
Block a user