[JAVA] Ich habe einen CRUD-Test mit SpringBoot + MyBatis + DBUnit geschrieben (Teil 1)

Einführung

In Vorheriger Artikel haben wir mit SpringBoot + JUnit5 eine Testklasse für die Controller-Ebene implementiert. Dieses Mal möchte ich die Implementierung der Service-Schicht und der Testklasse zusammenfassen, die DB-Operationen ausführen.

Da die Vorbereitung der zu testenden App jedoch etwas umfangreich ist, habe ich beschlossen, den Artikel in den ersten und den zweiten Teil zu unterteilen. Ich werde es mit der folgenden Konfiguration zusammenfassen.

** ・ ・ ・ Der erste Teil befasst sich nicht mit der Erstellung der wesentlichen Testklasse (Schweiß **)

[^ mybatis]: Sogenannter O / R-Mapper. Die Zuordnung zwischen Java und SQL ist einfach und leicht zu verstehen, und dynamisches SQL kann geschrieben werden. Es ist sehr praktisch, mit MyBatisGenerator Mapper, Model usw. sanft aus TBL erstellen zu können. (Wird in einem anderen Artikel vorgestellt)

[^ h2]: Java-Datenbanksoftware. Lightweight, JDBC verfügbar und kompatibel mit wichtigen DBs. Es ist seit langem beliebt für Lightweight-Apps, Demos und Tests. Ich werde es auch dieses Mal zu Testzwecken verwenden.

[^ dbunit]: Ein Unit-Test-Tool für Klassen, die Operationen an DBs ausführen, z. B. DAO und Repository. Es verfügt über alle Funktionen, die für Tests mit DB erforderlich sind, z. B. die Eingabe von Daten vor dem Test, die Überprüfung nach der Überprüfung und das Rollback nach dem Test.

Entwicklungsumgebung

OS : macOS Catalina IDE : IntelliJ Ultimate Java : 11 Gradle : 6.6.1 SpringBoot : 2.3.4 MySQL : 8.0.17

1. Datenbankvorbereitung

Bereiten Sie zunächst die DB vor, die von der Anwendung bedient werden soll. Unter der Annahme, dass der Hauptteil "MySQL" verwendet, verwenden wir "H2" für JUnit-Tests.

Durch das Trennen der Datenbank müssen Sie sich keine Sorgen machen, dass während des Tests versehentlich Daten gelöscht oder zerstört werden. Die integrierte Datenbank H2 ist praktisch, da Sie sich nicht um externe Verbindungen kümmern müssen und sie schnell startet. (Besonders perfekt zum Testen in einer CI / CD-Kostümumgebung)

Im ersten Teil werden wir eine lokale Umgebung mit MySQL vorbereiten.

1-1. Vorbereitung von MySQL

Die Verwendung von MySQL mit Docker ist einfach und unkompliziert. (Runder Wurf)

Nachdem Sie oben eine Verbindung zu MySQL als "Root" -Benutzer hergestellt haben, erstellen Sie "Datenbank" und "Benutzer" für diese Anwendung.

--Datenbank-Demo_Erstellen Sie db
CREATE DATABASE demo_db;
--Benutzername: Demo, Passwort:Demo, Autorität:demo_Alle Berechtigungen für db
CREATE USER 'demo'@'%' IDENTIFIED BY 'demo';
GRANT ALL PRIVILEGES ON demo_db.* TO 'demo'@'%';
FLUSH PRIVILEGES;

MySQL ist jetzt fertig.

1-2. Erstellen eines Spring Boot-Projekts

Das Spring Boot-Projekt basiert auf dem vorherigen (https://qiita.com/kilvis/items/d75461b3596bfb0f6759#1-%E3%83%86%E3%82%B9%E3%83%88%E5%AF%BE % E8% B1% A1% E3% 81% AE% E3% 82% A2% E3% 83% 97% E3% 83% AA% E3% 82% B1% E3% 83% BC% E3% 82% B7% E3 Fügen Sie MyBatis- und JDBC-Bibliotheken (MySQL) zu% 83% A7% E3% 83% B3% E3% 81% AE% E6% BA% 96% E5% 82% 99 hinzu.

build.gradle


dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.3' //hinzufügen
    compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.22' //hinzufügen
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'
}

1-3 Einstellen der Datenquelle für die App

Schreiben Sie die Verbindungseinstellungen in "MySQL" in "main / resources / application.yml" für die lokale Umgebung der App. Die Verbindungseinstellungen für den zuvor erstellten user: demo und Database: demo_db lauten wie folgt.

src/main/resources/application.yml


spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo_db
    username: demo
    password: demo
mybatis:
  configuration:
    map-underscore-to-camel-case: true

map-underscore-to-camel-case: true ordnet den Namen des Schlangenfalls dem Kamelfall zu, wenn das DB-Objekt und das Java-Objekt zugeordnet werden.

Damit sind die Verbindungseinstellungen für "MySQL" abgeschlossen.

1-4. Erstellen einer Tabelle

Erstellen Sie eine einfache Beispieltabelle.

Kundentabellenspezifikationen
Spaltenname Schimmel Einschränkungen usw.
id int Primärschlüssel für die automatische Nummerierung
name varchar(100) keine Nullbedingung
age int keine Nullbedingung
address varchar(200)

DDL

schema.sql


create table customer
(
    id int auto_increment,
    name varchar(100) not null,
    age int not null,
    address varchar(200) null,
    constraint customer_pk primary key (id)
);

DML Außerdem werde ich auch die ersten Eingabedaten machen.

data.sql


insert into
    customer (name, age, address)
VALUES
    ('Luke Skywalker', 19, 'Tatween'),
    ('Leia Organa', 19, 'Orderan'),
    ('Han Solo', 32, 'Correlia'),
    ('Darth Vader', 41, 'Tatween');

Führen Sie die obige DDL und DML mit MySQL aus und schreiben Sie sie fest, um die Tabelle und die Anfangsdaten einzurichten.

Speichern Sie außerdem die erstellte DDL als "schema.sql" und die DML als "data.sql" in "test / resources". Diese Dateien werden im zweiten Teil des JUnit-Tests verwendet.

├── build.gradle
└── src
    ├── main
    └── test
        ├── java
        └── resources
            ├── application.yml
            ├── schema.sql   // DDL
            └── data.sql     // DML

2. Erstellen eines Repositorys mit MyBatis

Erstellen Sie eine Repository-Klasse, um DB-Vorgänge auszuführen. Dieses Mal wird MyBatis für den O / R-Mapper verwendet. Befolgen Sie daher die Regeln

--Erstellen einer Modellklasse (Entität), die dem Ergebnis der Select-Klausel zugeordnet ist --Erstellen eines Mappers, der Model und CRUD SQL abbildet --Erstellung der Repository-Klasse mit Mapper

Ich werde es in der Reihenfolge von machen.

2-1. Erstellen einer Modellklasse (Entität)

Erstellen Sie eine Modellklasse, die die Daten für eine Zeile der zuvor erstellten "Kunden" -Tabelle enthält.

Customer.java


package com.example.dbunitdemo.domain.model;

import lombok.Builder;
import lombok.Data;

@Builder
@Data
public class Customer {
    private Long id;
    private String name;
    private Integer age;
    private String address;
}

Es ist einfach, da der Accessor und toString () dank @ lombok.Data automatisch erstellt werden.

2-2. Mapper erstellen

Erstellen Sie einen Mapper, der die zuvor erstellte Klasse "Customer" mit dem SQL von CRUD verbindet. Mapper wird aus zwei Java-Schnittstellen und einer XML-Datei erstellt, die SQL beschreiben.

CustomerMapper.java

java:com.example.dbunitdemo.domain.mapper.CustomerMapper.java


package com.example.dbunitdemo.domain.mapper;

import com.example.dbunitdemo.domain.model.Customer;
import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface CustomerMapper {
    List<Customer> findAll();
    Customer get(@Param("id") Long id);
    int insert(@Param("customer") Customer customer);
    int update(@Param("customer") Customer customer);
    int delete(@Param("id") Long id);
}

@ Param gibt den Namen an, der auf das Argument in der unten beschriebenen XML-SQL-Anweisung verweist.

CustomerMappler.xml

main/resources/com/example/dbunitdemo/domain/mapper/CustomerMapper.xml


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dbunitdemo.domain.mapper.CustomerMapper">
    <select id="findAll" resultType="com.example.dbunitdemo.domain.model.Customer">
        SELECT id, name, age, address FROM customer
    </select>
    <select id="get" resultType="com.example.dbunitdemo.domain.model.Customer">
        SELECT id, name, age, address FROM customer WHERE id = #{id}
    </select>
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO customer (name, age, address) VALUES (#{customer.name}, #{customer.age}, #{customer.address})
    </insert>
    <update id="update">
        UPDATE customer SET name = #{customer.name}, age = #{customer.age}, address = #{customer.address} WHERE id = #{customer.id}
    </update>
    <delete id="delete">
        DELETE FROM customer WHERE id = #{id}
    </delete>
</mapper>
Ergänzung: Hinweise zum Erstellen von XML für Mapper

--Erstellen Sie dieselbe Verzeichnishierarchie wie die Java-Pakethierarchie unter "main / resources" und erstellen Sie eine "(Mapper-Name) .xml" -Datei.

AppConfig.java

Geben Sie abschließend das Paket an, zu dem die Mapper-Schnittstelle mit der Annotation der Konfigurationsklasse gehört.

AppConfig.java


package com.example.dbunitdemo.config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.example.dbunitdemo.domain.mapper") //Geben Sie das Paket an, zu dem Mapper gehört
public class AppConfig {
   // ...Kürzung
}

Damit ist die Erstellung von "CustomerMapper" abgeschlossen.

Die Verzeichnisstruktur nach dem Erstellen von Mapper ist wie folgt.

├── main
│   ├── java
│   │   └── com
│   │       └── example
│   │           └── dbunitdemo
│   │               ├── DbunitDemoApplication.java
│   │               ├── config
│   │               │   └── AppConfig.java
│   │               └── domain
│   │                   ├── mapper
│   │                   │   └── CustomerMapper.java
│   │                   └── model
│   │                       └── Customer.java
│   └── resources
│       ├── application.yml
│       ├── com
│       │   └── example
│       │       └── dbunitdemo
│       │           └── domain
│       │               └── mapper
│       │                   └── CustomerMapper.xml

2-3. Erstellen einer Repository-Klasse mit Mapper

Verwenden Sie den einfachen DI Mapper aus Repository.

CustomerRepository.java


package com.example.dbunitdemo.domain.repository;

import com.example.dbunitdemo.domain.mapper.CustomerMapper;
import com.example.dbunitdemo.domain.model.Customer;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class CustomerRepository {

  private final CustomerMapper customerMapper;

  public List<Customer> findAll() {
    return customerMapper.findAll();
  }

  public Customer get(Long id) {
    return customerMapper.get(id);
  }

  public int create(Customer customer) {
    return customerMapper.insert(customer);
  }

  public int update(Customer customer) {
    return customerMapper.update(customer);
  }

  public int delete(Long id) {
    return customerMapper.delete(id);
  }
}

Es mag wie eine bedeutungslose Klasse erscheinen, nur um "Mapper" zu verpacken. Dies ist notwendig, um "Service" ** unabhängig von Infrastruktur und Middleware ** zu machen.

Wenn Sie beispielsweise "Mapper" direkt von "Service" aus verwenden, ohne "Repository" zu durchlaufen, können Sie die MyBatis-spezifische Verarbeitung (z. B. Abfragekonstruktion mit Beispiel) in der Logik von "Service" verwenden, oder wenn Sie nicht gut in DB sind, verwenden Sie MySQL. Es besteht die Möglichkeit, dass eine Verarbeitung implementiert wird, die sich etwas bewusst ist.

"Service" sollte sich auf die Verwaltung von "Repository" -Transaktionen konzentrieren und keine infrastruktur- oder Middleware-abhängige Verarbeitung implementieren. Erstellen Sie ein Repository, um solche Teile auszublenden.

3. Überprüfen Sie den Betrieb

Nachdem ich es bisher gemacht habe, möchte ich den Vorgang überprüfen, damit ich es schnell mit Repository-> Service-> Controller verbinden kann. Lassen Sie es uns zunächst nur in der Methode "findAll" implementieren, um die Anzeige der Anfangsdaten der Datenbank zu überprüfen.

CustomerService.java


@Service
@RequiredArgsConstructor
public class CustomerService {
  private final CustomerRepository customerRepository;

  @Transactional(readOnly = true)
  public List<Customer> findAll() {
    return customerRepository.findAll();
  }
}

CustomerController.java



@RequiredArgsConstructor
@RestController
public class CustomerController {
    private final CustomerService customerService;

    @GetMapping("customers")
    public List<Customer> findAll() {
        return customerService.findAll();
    }
}

Starten Sie die Anwendung nach dem bisherigen Erstellen mit bootRun und versuchen Sie, über den Browser auf http: // localhost: 8080 / customers zuzugreifen. image.png

Die sicher eingegebenen Daten werden angezeigt!

Fortsetzung des zweiten Teils ...

Im ersten Teil habe ich die Einstellung von "MySQL" eingeführt, die Implementierung von "Mapper" von MyBatis und "Repository", das es verwendet. Im zweiten Teil werden wir die Implementierung des Unit-Tests mit DBUnit (und JUnit5) vorstellen.

Recommended Posts

Ich habe einen CRUD-Test mit SpringBoot + MyBatis + DBUnit geschrieben (Teil 1)
Ich habe jetzt einen Test mit Spring Boot + JUnit 5 geschrieben
Erstellen Sie ein Eltern-Kind-Beziehungsformular mit form_object (ich habe auch einen Test geschrieben)
04. Ich habe mit SpringBoot + Thymeleaf ein Frontend gemacht
Ich habe ein Programm zur Beurteilung von Primzahlen in Java geschrieben
Erstellen Sie eine einfache CRUD mit SpringBoot + JPA + Thymeleaf ~ ~ Validierung hinzufügen ~
Erstellen Sie mit SpringBoot + JPA + Thymeleaf ein einfaches CRUD ~ ~ Hallo Welt ~
Erstellen Sie eine einfache CRUD mit SpringBoot + JPA + Thymeleaf ⑤ ~ Common template ~
Ich habe versucht, eine PDF-Datei mit Java part2 zu verarbeiten
Benötige ich einen Test, wenn ich DDD in einer Sprache mit einem Typ mache?
Erstellen Sie eine einfache CRUD mit SpringBoot + JPA + Thymeleaf ④ ~ Fehlermeldung anpassen ~
Ich habe versucht, Spring + Mybatis + DbUnit zu verwenden
REST-API-Test mit REST Assured Part 2
Ich habe mit Swing eine GUI erstellt
Erstellen Sie eine einfache CRUD mit SpringBoot + JPA + Thymeleaf ② ~ Bildschirm- und Funktionserstellung ~
01. Ich habe versucht, eine Umgebung mit SpringBoot + IntelliJ + MySQL (MyBatis) (Windows 10) zu erstellen.
Ich habe eine Lambda-Funktion in Java geschrieben und mit SAM bereitgestellt
Ich möchte einen Unit Test schreiben!
Ich habe versucht, OnlineConverter mit SpringBoot + JODConverter zu verwenden
Ich habe versucht, ein wenig mit BottomNavigationView zu spielen ①
Ich habe mit Ruby einen riskanten Würfel gemacht
Extrahieren Sie einen Teil einer Zeichenfolge in Ruby
Ich habe eine Janken App mit Kotlin gemacht
Verteilte Transaktion mit SpringBoot + PostgreSql + mybatis + NarayanaJTA
Deserialisieren Sie XML mit Spring-Boot in eine Sammlung
Ich fand MyBatis nützlich, also habe ich es geschrieben.
Ich habe eine Janken App mit Android gemacht
[SpringBoot] So schreiben Sie einen Controller-Test
Ich habe eine App für maschinelles Lernen mit Dash (+ Docker) Teil 3 ~ Übung ~ erstellt
Ich habe eine Jenkins-Datei mit deklarativer Pipeline geschrieben (Checkstyle, Findbugs, PMD, CPD usw.)
So testen Sie eine Klasse, die application.properties mit SpringBoot verarbeitet (Anfrage: darauf hingewiesen)