![Test d'intégration d'une base de données utilisant MariaDB pour remplacer MySql - 3](https://cdn.javarush.com/images/article/6270633c-1cfa-4b46-aefc-4e5802ab06bd/1024.jpeg)
Structure du projet
Seules les parties concernées sont affichées :![Test d'intégration d'une base de données utilisant MariaDB pour remplacer MySql - 5](https://cdn.javarush.com/images/article/261272f7-bc93-4174-ad23-5e6dec4c1162/1024.jpeg)
![Test d'intégration d'une base de données utilisant MariaDB pour remplacer MySql - 6](https://cdn.javarush.com/images/article/8d8d0ffa-8898-454b-a100-d3e31ef73e73/1024.jpeg)
CREATE TABLE `robots`
(
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`name` CHAR(255) CHARACTER SET utf8 NOT NULL,
`cpu` CHAR(255) CHARACTER SET utf8 NOT NULL,
`producer` CHAR(255) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
L'entité représentant cette table :
@Builder
@Data
public class Robot {
private Long id;
private String name;
private String cpu;
private String producer;
}
Interface pour le référentiel testé :
public interface RobotDAO {
Robot findById(Long id);
Robot create(Robot robot);
List<Robot> findAll();
Robot update(Robot robot);
void delete(Long id);
}
En fait, voici des opérations CRUD standard, sans exotiques, nous considérerons donc la mise en œuvre non pas de toutes les méthodes (enfin, cela ne surprendra personne), mais de certaines - pour plus de concision :
@Repository
@AllArgsConstructor
public class RobotDAOImpl implements RobotDAO {
private static final String FIND_BY_ID = "SELECT id, name, cpu, producer FROM robots WHERE id = ?";
private static final String UPDATE_BY_ID = "UPDATE robots SET name = ?, cpu = ?, producer = ? WHERE id = ?";
@Autowired
private final JdbcTemplate jdbcTemplate;
@Override
public Robot findById(Long id) {
return jdbcTemplate.queryForObject(FIND_BY_ID, robotMapper(), id);
}
@Override
public Robot update(Robot robot) {
jdbcTemplate.update(UPDATE_BY_ID,
robot.getName(),
robot.getCpu(),
robot.getProducer(),
robot.getId());
return robot;
}
private RowMapper<Robot> robotMapper() {
return (rs, rowNum) ->
Robot.builder()
.id(rs.getLong("id"))
.name(rs.getString("name"))
.cpu(rs.getString("cpu"))
.producer(rs.getString("producer"))
.build();
}
Faisons une petite digression et voyons ce qui se passe avec nos dépendances (seules celles utilisées pour la partie démontrée de l'application sont présentées) :
<dependencies>
<dependency>
<groupId>org.mariadb.jdbc</groupId>
<artifactId>mariadb-java-client</artifactId>
<version>2.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.craftercms.mariaDB4j</groupId>
<artifactId>mariaDB4j-springboot</artifactId>
<version>2.4.2.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.2.1.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
</dependencies>
4 - dépendance pour la base de données MariaDb elle-même 10 - dépendance pour la connexion avec SpringBoot 16 - Lombok (enfin, je pense que tout le monde sait de quel type de bibliothèque il s'agit) 22 - démarreur pour les tests (où le JUnit dont nous avons besoin est intégré) 28 - démarreur pour travailler avec springJdbc Jetons un coup d'œil au conteneur Spring avec les beans nécessaires à nos tests (en particulier le bean de création MariaDB) :
@Configuration
public class TestConfigDB {
@Bean
public MariaDB4jSpringService mariaDB4jSpringService() {
return new MariaDB4jSpringService();
}
@Bean
public DataSource dataSource(MariaDB4jSpringService mariaDB4jSpringService) {
try {
mariaDB4jSpringService.getDB().createDB("testDB");
} catch (ManagedProcessException e) {
e.printStackTrace();
}
DBConfigurationBuilder config = mariaDB4jSpringService.getConfiguration();
return DataSourceBuilder
.create()
.username("root")
.password("root")
.url(config.getURL("testDB"))
.driverClassName("org.mariadb.jdbc.Driver")
.build();
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
5 - le composant principal pour élever MariaDB (pour les applications basées sur Spring Framework) 10 - définir un bean de base de données 12 - définir le nom de la base de données créée 17 - extraire les configurations pour notre cas 19 - construire une base de données à l'aide du modèle Builder ( un bon aperçu du modèle ) Et enfin, tout le bruit concerne le bean JdbcTemplate pour la communication avec la base de données en cours de création. L'idée est que nous aurons une classe principale pour les tests Tao, dont hériteront toutes les classes de tests Tao, dont les tâches incluent :
- lancer certains scripts utilisés dans la base de données principale (scripts de création de tables, de modification de colonnes et autres) ;
- lancer des scripts de test qui remplissent les tableaux avec des données de test ;
- suppression de tableaux.
@SpringBootTest(classes = TestConfigDB.class)
public abstract class DataBaseIT {
@Autowired
private JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void fillDataBase(String[] initList) {
for (String x : initList) {
try {
jdbcTemplate.update(IOUtils.resourceToString("/db.migrations/" + x, StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void cleanDataBase() {
getJdbcTemplate().update("DROP database testDB");
getJdbcTemplate().update("CREATE database testDB");
getJdbcTemplate().update("USE testDB");
}
public void fillTables(String[] fillList) {
for (String x : fillList) {
try {
Stream.of(
IOUtils.resourceToString("/fill_scripts/" + x, StandardCharsets.UTF_8))
.forEach(jdbcTemplate::update);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1 - en utilisant l'annotation @SpringBootTest, nous définissons une configuration de test 11 - comme argument dans cette méthode, nous transmettons les noms des tables dont nous avons besoin, et lui, en tant que travailleur acharné responsable, les chargera pour nous (ce qui nous donne l'opportunité pour réutiliser cette méthode autant que notre cœur le désire) 21 - nous utilisons cette méthode pour nettoyer, à savoir supprimer toutes les tables (et leurs données) de la base de données 27 - l'argument dans cette méthode est un tableau de noms de scripts avec des données de test qui sera chargé pour tester une méthode spécifique. Notre script avec les données de test :
INSERT INTO robots(name, cpu, producer)
VALUES ('Rex', 'Intel Core i5-9400F', 'Vietnam'),
('Molly', 'AMD Ryzen 7 2700X', 'China'),
('Ross', 'Intel Core i7-9700K', 'Malaysia')
Et maintenant ce pour quoi nous sommes tous rassemblés aujourd'hui.
Cours de test Tao
@RunWith(SpringRunner.class)
public class RobotDataBaseIT extends DataBaseIT {
private static RobotDAO countryDAO;
@Before
public void fillData() {
fillDataBase(new String[]{
"create_table_robots.sql"
});
countryDAO = new RobotDAOImpl(getJdbcTemplate());
}
@After
public void clean() {
cleanDataBase();
}
private RowMapper<Robot> robotMapper() {
return (rs, rowNum) ->
Robot.builder()
.id(rs.getLong("id"))
.name(rs.getString("name"))
.cpu(rs.getString("cpu"))
.producer(rs.getString("producer"))
.build();
}
2 - nous héritons de la classe principale pour nos tests 4 - notre référentiel testé 7 - une méthode qui sera lancée avant chaque test 8 - nous utilisons la méthode de la classe parent pour charger les tables nécessaires 11 - nous initialisons notre dao 15 - une méthode qui sera lancé après chaque test, nettoyant notre base de données 19 - implémentation de notre RowMapper, analogue à la classe Tao Nous utilisons @Before et @After, qui sont utilisés avant et après une méthode de test, mais nous pourrions prendre une lib qui nous permet utiliser des annotations liées au début des tests d'exécutions de cette classe et à la fin. Par exemple celui-ci , qui accélérerait considérablement les tests, puisqu'il faudrait créer et supprimer complètement des tables à chaque fois, et une fois par classe. Mais nous ne le faisons pas. Pourquoi demandes-tu? Que se passe-t-il si l'une des méthodes modifie la structure du tableau ? Par exemple, supprimez une colonne. Dans ce cas, les méthodes restantes peuvent échouer ou doivent répondre comme prévu (par exemple, créer une colonne arrière). Nous devons admettre que cela nous donne une connexion (dépendance) inutile des tests les uns par rapport aux autres, ce qui ne nous est d'aucune utilité. Mais je m'éloigne du sujet, continuons...
Tester la méthode findById
@Test
public void findByIdTest() {
fillTables(new String[]{"fill_table_robots.sql"});
Long id = getJdbcTemplate().queryForObject("SELECT id FROM robots WHERE name = 'Molly'", Long.class);
Robot robot = countryDAO.findById(id);
assertThat(robot).isNotNull();
assertThat(robot.getId()).isEqualTo(id);
assertThat(robot.getName()).isEqualTo("Molly");
assertThat(robot.getCpu()).isEqualTo("AMD Ryzen 7 2700X");
assertThat(robot.getProducer()).isEqualTo("China");
}
3 - remplir le tableau avec les données de test 5 - obtenir l'identifiant de l'entité dont nous avons besoin 6 - utiliser la méthode testée 8...12 - comparer les données reçues avec celles attendues
Test de méthode de mise à jour
@Test
public void updateTest() {
fillTables(new String[]{"fill_table_robots.sql"});
Long robotId = getJdbcTemplate().queryForObject("SELECT id FROM robots WHERE name = 'Rex'", Long.class);
Robot updateRobot = Robot.builder()
.id(robotId)
.name("Aslan")
.cpu("Intel Core i5-3470")
.producer("Narnia")
.build();
Robot responseRobot = countryDAO.update(updateRobot);
Robot updatedRobot = getJdbcTemplate().queryForObject(
"SELECT id, name, cpu, producer FROM robots WHERE id = ?",
robotMapper(),
robotId);
assertThat(updatedRobot).isNotNull();
assertThat(updateRobot.getName()).isEqualTo(responseRobot.getName());
assertThat(updateRobot.getName()).isEqualTo(updatedRobot.getName());
assertThat(updateRobot.getCpu()).isEqualTo(responseRobot.getCpu());
assertThat(updateRobot.getCpu()).isEqualTo(updatedRobot.getCpu());
assertThat(updateRobot.getProducer()).isEqualTo(responseRobot.getProducer());
assertThat(updateRobot.getProducer()).isEqualTo(updatedRobot.getProducer());
assertThat(responseRobot.getId()).isEqualTo(updatedRobot.getId());
assertThat(updateRobot.getId()).isEqualTo(updatedRobot.getId());
}
3 - remplir le tableau avec les données de test 5 - obtenir l'identifiant de l'entité en cours de mise à jour 7 - construire l'entité mise à jour 14 - utiliser la méthode en cours de test 15 - obtenir l'entité mise à jour pour vérification 20...28 - comparer les données reçues avec ceux attendus Tester la méthode de mise à jour est similaire à créer. Au moins pour moi. Vous pouvez modifier les rapprochements autant que vous le souhaitez : il n'y aura jamais trop de chèques. Je voudrais également noter que les tests ne garantissent pas la pleine fonctionnalité ni l'absence de bugs. Les tests garantissent uniquement que le résultat réel du programme (son fragment) correspond à celui attendu. Dans ce cas, seules les parties pour lesquelles des tests ont été rédigés sont vérifiées.
Commençons un cours avec des tests...
![Test d'intégration d'une base de données utilisant MariaDB pour remplacer MySql - 7](https://cdn.javarush.com/images/article/de92a3ca-b8d0-4851-845f-9319f30828d8/original.jpeg)
![Test d'intégration d'une base de données utilisant MariaDB pour remplacer MySql - 8](https://cdn.javarush.com/images/article/7cdd0ce2-ea39-4e8b-b499-522b2afb0fa0/original.jpeg)
Liens utiles
- Un bon article sur la partie non examinée de cette pile technologique.
- Une série d'articles intéressante sur Maven, Spring, MySQL, Hibernate.
- Rafraîchissons-nous un peu la mémoire sur les tests unitaires.
- Un exemple intéressant de tests d'intégration, mais avec substitution PostgreSQL.
- De nombreuses personnes, et pas seulement lors des tests, utilisent MariaDB au lieu de MySql.
![Test d'intégration d'une base de données utilisant MariaDB pour remplacer MySql - 9](https://cdn.javarush.com/images/article/151b0636-70a0-46c3-80e0-8307327ef4dc/1024.jpeg)
*musique épique de Star Wars*
GO TO FULL VERSION