Tietokantavuorovaikutusten testaaminen
Kirjoittakaa integraatiotestejä tietojen käyttökerroksille ja varmistakaa oikea vuorovaikutus relaatiotietokantojen kanssa.
Tietokantavuorovaikutusten testaaminen on ilmainen Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Testauksen hallinta: JUnit, Mockito ja integraatiotestit-kurssilla on yhteensä 4 oppituntia.
Miksi tietokantavuorovaikutusta testataan?
Tietokantavuorovaikutus on useimpien sovellusten keskeinen osa. Sen testaaminen varmistaa, että sovellus tallentaa, hakee ja päivittää tietoja luotettavasti.
- Tietojen eheys: Varmistaa, että tiedot tallennetaan oikein.
- Liiketoimintalogiikka: Varmistaa tietoihin liittyvien liiketoimintasääntöjen toiminnan.
- Virheiden ehkäisy: Havaitsee ongelmat ennen kuin ne päätyvät tuotantoon.
Tuotantotietokantojen haasteet
Suoraan todellisen tuotantotietokannan kanssa testaaminen voi olla hankalaa ja johtaa epäluotettaviin testeihin:
- Hitaus: Todelliset tietokannat pidentävät testikokonaisuuksien suoritusaikaa merkittävästi.
- Tila: Testit voivat jättää jälkeensä tietoja, jotka vaikuttavat seuraaviin testeihin.
- Monimutkainen määritys: Edellyttää käynnissä olevaa ulkoista palvelua ja tiettyjä määrityksiä.
- Eristäminen: Jokaisen testin suorittamista eristetyssä ympäristössä on vaikea varmistaa.
Muistinsisäiset tietokannat apuun
Näiden haasteiden ratkaisemiseksi integraatiotesteissä käytetään usein muistinsisäisiä tietokantoja. Ne ovat kevyitä tietokantoja, jotka toimivat kokonaan sovelluksen muistissa.
- Nopeus: Levyn I/O-operaatioita ei tarvita, joten käynnistys ja sammutus ovat nopeita.
- Eristys: Jokainen testiajo voi alkaa uudesta ja tyhjästä tietokannasta.
- Helppo määritys: Usein tarvitaan vain riippuvuus ja yhteyden URL-osoite.
Suosittuja vaihtoehtoja ovat H2, HSQLDB ja Apache Derby.
H2-tietokannan määrittäminen
Katsotaan, kuinka helppoa H2-muistinsisäiseen tietokantaan yhdistäminen on tavallista JDBC:tä käyttämällä. Se toimii aivan tavallisen tietokannan tavoin, mutta sijaitsee sovelluksen muistissa.
Tarvitsette H2-riippuvuuden, esimerkiksi Mavenissa: com.h2database:h2.
import java.sql.*;
public class H2Demo {
public static void main(String[] args) throws SQLException {
String jdbcUrl = "jdbc:h2:mem:testdb";
String username = "sa";
String password = "";
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
Statement stmt = conn.createStatement();
stmt.execute("CREATE TABLE products (id INT PRIMARY KEY, name VARCHAR(255))");
stmt.executeUpdate("INSERT INTO products (id, name) VALUES (1, 'Laptop')");
ResultSet rs = stmt.executeQuery("SELECT * FROM products");
if (rs.next()) {
System.out.println("Product: " + rs.getString("name"));
}
}
}
}Tietojen käyttökerroksen esittely
Sovelluksessanne käytetään yleensä Data Access Object (DAO)- tai Repository-suunnittelumallia tietokannan käsittelyyn. Tämä kerros piilottaa matalan tason JDBC- tai ORM-yksityiskohdat.
Käytämme yksinkertaista ProductRepository-komponenttia Product-olioiden hallintaan.
public class Product {
private int id;
private String name;
public Product(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() { return id; }
public String getName() { return name; }
}
import java.util.List;
public interface ProductRepository {
void save(Product product);
Product findById(int id);
List<Product> findAll();
}Yksinkertaisen repositoryn toteuttaminen
Tässä on ProductRepository-komponentin perusimplementaatio raakaa JDBC:tä käyttäen. Todellisessa sovelluksessa voitaisiin käyttää Springin JdbcTemplate-luokkaa tai Hibernate-tyyppistä ORM:ää.
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
// Product class and ProductRepository interface as defined previously
public class JdbcProductRepository implements ProductRepository {
private Connection conn;
public JdbcProductRepository(Connection conn) {
this.conn = conn;
try (Statement stmt = conn.createStatement()) {
stmt.execute("CREATE TABLE IF NOT EXISTS products (id INT PRIMARY KEY, name VARCHAR(255))");
} catch (SQLException e) { throw new RuntimeException(e); }
}
@Override
public void save(Product product) {
String sql = "INSERT INTO products (id, name) VALUES (?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, product.getId());
ps.setString(2, product.getName());
ps.executeUpdate();
} catch (SQLException e) { throw new RuntimeException(e); }
}
@Override
public Product findById(int id) {
String sql = "SELECT id, name FROM products WHERE id = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id); ResultSet rs = ps.executeQuery();
if (rs.next()) { return new Product(rs.getInt("id"), rs.getString("name")); }
} catch (SQLException e) { throw new RuntimeException(e); }
return null;
}
@Override
public List<Product> findAll() {
List<Product> products = new ArrayList<>();
String sql = "SELECT id, name FROM products";
try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
products.add(new Product(rs.getInt("id"), rs.getString("name")));
}
} catch (SQLException e) { throw new RuntimeException(e); }
return products;
}
}Repositoryn testaaminen – määritys
Kirjoitetaan nyt yksinkertainen ohjelma JdbcProductRepository-komponentin testaamiseen. Määritämme H2-muistinsisäisen tietokannan juuri tätä testiajoa varten.
Huomatkaa, että luomme repositorylle uuden tietokantayhteyden, mikä varmistaa eristyksen.
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
// Product class (simplified for mobile)
class Product {
private int id; private String name;
public Product(int id, String name) { this.id = id; this.name = name; }
public int getId() { return id; }
public String getName() { return name; }
}
// ProductRepository interface
interface ProductRepository {
void save(Product product);
Product findById(int id);
List<Product> findAll();
}
// JdbcProductRepository (simplified for mobile)
class JdbcProductRepository implements ProductRepository {
private Connection conn;
public JdbcProductRepository(Connection conn) {
this.conn = conn;
try (Statement stmt = conn.createStatement()) {
stmt.execute("CREATE TABLE IF NOT EXISTS products (id INT PRIMARY KEY, name VARCHAR(255))");
} catch (SQLException e) { throw new RuntimeException(e); }
}
@Override public void save(Product product) {
String sql = "INSERT INTO products (id, name) VALUES (?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, product.getId()); ps.setString(2, product.getName());
ps.executeUpdate();
} catch (SQLException e) { throw new RuntimeException(e); }
}
@Override public Product findById(int id) { /* ... omitted ... */ return null; }
@Override public List<Product> findAll() { /* ... omitted ... */ return new ArrayList<>(); }
}
public class ProductRepositoryTestRunner {
public static void main(String[] args) throws SQLException {
String jdbcUrl = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1";
try (Connection conn = DriverManager.getConnection(jdbcUrl, "sa", "")) {
System.out.println("DB connection established.");
ProductRepository repository = new JdbcProductRepository(conn);
Product laptop = new Product(1, "Laptop");
repository.save(laptop);
System.out.println("Saved product: " + laptop.getName());
Product foundProduct = repository.findById(1);
System.out.println("Found product: " + (foundProduct != null ? foundProduct.getName() : "None"));
List<Product> allProducts = repository.findAll();
System.out.println("Total products: " + allProducts.size());
}
}
}Tietokannan tilan tarkistaminen
Oikeassa testissä pelkkä tulostaminen ei riitä. Teidän on väitettävä, että tietokannan tila vastaa odotuksia toiminnon suorittamisen jälkeen. Näin varmistetaan DAO-metodien oikea toiminta.
Lisätään muutama perus tarkistus tulosten varmistamiseksi.
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
// Product class (simplified for mobile)
class Product {
private int id; private String name;
public Product(int id, String name) { this.id = id; this.name = name; }
public int getId() { return id; }
public String getName() { return name; }
}
// ProductRepository interface
interface ProductRepository {
void save(Product product); Product findById(int id); List<Product> findAll();
}
// JdbcProductRepository (simplified for mobile)
class JdbcProductRepository implements ProductRepository {
private Connection conn;
public JdbcProductRepository(Connection conn) { /* ... omitted ... */ this.conn = conn; }
@Override public void save(Product product) { /* ... omitted ... */ }
@Override public Product findById(int id) {
String sql = "SELECT id, name FROM products WHERE id = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id); ResultSet rs = ps.executeQuery();
if (rs.next()) { return new Product(rs.getInt("id"), rs.getString("name")); }
} catch (SQLException e) { throw new RuntimeException(e); }
return null;
}
@Override public List<Product> findAll() {
List<Product> products = new ArrayList<>();
String sql = "SELECT id, name FROM products";
try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) { products.add(new Product(rs.getInt("id"), rs.getString("name"))); }
} catch (SQLException e) { throw new RuntimeException(e); }
return products;
}
}
public class ProductRepositoryAssertions {
public static void main(String[] args) throws SQLException {
String jdbcUrl = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1";
try (Connection conn = DriverManager.getConnection(jdbcUrl, "sa", "")) {
ProductRepository repository = new JdbcProductRepository(conn);
Product laptop = new Product(1, "Laptop");
repository.save(laptop);
// Assertion 1: Check if product was saved
Product found = repository.findById(1);
if (found != null && found.getName().equals("Laptop")) {
System.out.println("Test Passed: Product saved & found.");
} else { System.out.println("Test Failed: Product not found or name mismatch."); }
// Assertion 2: Check total count
List<Product> all = repository.findAll();
if (all.size() == 1) {
System.out.println("Test Passed: Correct product count.");
} else { System.out.println("Test Failed: Incorrect product count."); }
}
}
}Puhtaiden testien varmistaminen transaktioilla
Testien eristyksen parantamiseksi, erityisesti Springin kaltaisia kehyksiä käytettäessä, voitte hyödyntää transaktioita.
Kun merkitsette testimetodit @Transactional-annotaatiolla, kaikki testin aikana tietokantaan tehdyt muutokset perutaan automaattisesti testin päätyttyä. Näin tietokanta jää puhtaaseen tilaan seuraavaa testiä varten.
- Automaattinen siivous: Manuaalisia
DELETE-lauseita ei tarvita. - Eristys: Jokainen testi suoritetaan ikään kuin se olisi ainoa testi.
- Nopeus: Muutosten peruminen on usein nopeampaa kuin tietojen poistaminen ja lisääminen uudelleen.
Tietokantatestauksen parhaat käytännöt
Jotta tietokannan integraatiotestit olisivat tehokkaita ja helposti ylläpidettäviä, huomioikaa seuraavat vinkit:
- Käyttäkää muistinsisäisiä tietokantoja: Nopeuden ja eristyksen vuoksi.
- Pitäkää määritys suppeana: Luokaa vain kyseisessä testissä tarvittavat taulut ja tiedot.
- Käyttäkää transaktiollisia testejä: Perukaa muutokset automaattisesti.
- Tehkää selkeät väitteet: Varmistakaa odotetut tiedot ja tila.
- Keskittykää DAO-kerrokseen: Testatkaa tässä tietojen käyttökerrosta, älkää liiketoimintalogiikkaa.
Pikatarkistus: tietokantatestaus
Mikä seuraavista on H2:n kaltaisen muistinsisäisen tietokannan käytön ensisijainen hyöty integraatiotesteissä?
Kertaus: tietokantavuorovaikutuksen testaaminen
Tässä oppitunnissa opimme testaamaan tietokantavuorovaikutusta tehokkaasti.
- Ymmärsimme todellisten tietokantojen testaamisen haasteet.
- Tutustuimme H2:n kaltaisiin muistinsisäisiin tietokantoihin nopeana ja eristettynä ratkaisuna.
- Näimme, miten H2-tietokanta määritetään ja sitä käytetään ohjelmallisesti.
- Harjoittelimme Data Access Object (DAO)-komponentin testien kirjoittamista ja tietojen eheyden sekä oikean toiminnan varmistamista.
- Tutustuimme transaktionaalisiin testeihin automaattista siivousta varten.
Jatkakaa harjoittelua, jotta sovelluksenne tietokerros pysyy vankkana!
Opi Testauksen hallinta: JUnit, Mockito ja integraatiotestit tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 12
- Oppitunnit
- 48
Usein kysytyt kysymykset
Onko oppitunti ”Tietokantavuorovaikutusten testaaminen” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppimispolun 3 oppituntia, myös oppitunnin “Tietokantavuorovaikutusten testaaminen”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Testauksen hallinta: JUnit, Mockito ja integraatiotestit-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Tietokantavuorovaikutusten testaaminen”?
Kirjoittakaa integraatiotestejä tietojen käyttökerroksille ja varmistakaa oikea vuorovaikutus relaatiotietokantojen kanssa. Harjoittelet Testauksen hallinta: JUnit, Mockito ja integraatiotestit-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Testauksen hallinta: JUnit, Mockito ja integraatiotestit-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.
Kuinka kauan ”Tietokantavuorovaikutusten testaaminen”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppitunnilla?
Kyllä. Jokainen Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Yksikkö- ja integraatiotestit
- Integraatiotestien määrittäminen
- Tietokantavuorovaikutusten testaaminen
- Ulkoisten rajapintojen testaaminen WireMockilla