JavaRush /Java блогу /Random-KY /MySql алмаштыруу үчүн MariaDB аркылуу маалымат базасын ин...
Константин
Деңгээл

MySql алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөө

Группада жарыяланган
MySql - 1 алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөөБүгүн мен тестирлөө жөнүндө айткым келет, анткени code канчалык көп тесттер менен камтылса, ал ошончолук жакшы жана ишенимдүү деп эсептелет. Бирдикти тестирлөө жөнүндө эмес, маалымат базаларын интеграциялык тестирлөө жөнүндө сүйлөшөлү. Бирдик тесттери менен интеграциялык тесттердин ортосунда кандай айырма бар? MySql - 2 алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөөМодулдук (бирдик) бул программаны жеке модулдардын, методдордун же класстардын деңгээлинде тестирлөө, башкача айтканда, тесттер тез жана жеңил болуп, функциянын эң бөлүнүүчү бөлүктөрүнө таасир этет. Алар ошондой эле "ар бир ыкма үчүн бир сыноо" деп аталат. Интеграциялар жайыраак жана оор жана бир нече модулдардан жана кошумча функциялардан турушу мүмкүн. MySql - 3 алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөөЭмне үчүн тесттер дао (Data Access Object) катмарынын интеграциялык тесттери болуп саналат? Анткени маалымат базасына суроо менен методдорду сынап көрүү үчүн, биз оперативдик эстутумда негизгисин алмаштырып, өзүнчө маалымат базасын көтөрүшүбүз керек. Идея биз керектүү tableларды түзүп, аларды тесттик маалыматтар менен толтурабыз жана репозиторий классынын методдорунун тууралыгын текшеребиз (анткени, биз белгилүү бир учурда акыркы жыйынтык кандай болушу керектигин билебиз). Ошентип, баштайлы. Маалыматтар базасын туташтыруу боюнча темалар көптөн бери эле камтылган, ошондуктан бүгүн мен бул жөнүндө токтолгум келбейт жана биз программанын бизди кызыктырган бөлүктөрүн гана карап чыгабыз. Демейки боюнча, биздин тиркеме Spring Boot'ка негизделгендигинен баштайбыз, жазгы JDBC дао катмары үчүн (тактоо үчүн), биздин негизги маалымат базабыз MySQL болуп саналат жана биз аны MariaDB аркылуу алмаштырабыз (алар максималдуу түрдө шайкеш келет жана Демек, MySQL скрипттери эч качан MariaDB диалекти менен эч кандай карама-каршылыктар болбойт, анткени H2 менен болот). Ошондой эле биз шарттуу түрдө биздин программа маалымат базасынын схемасына өзгөртүүлөрдү башкаруу жана колдонуу үчүн Liquibase колдонот деп ойлойбуз жана ошого жараша бардык колдонулган скрипттер биздин тиркемеде сакталат.

Долбоордун структурасы

Жабыркаган бөлүктөр гана көрсөтүлөт: MySql - 5 алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөөОоба, бүгүн биз роботторду түзөбүз)) MySql - 6 алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөөТаблица үчүн скрипт, биз бүгүн сынай турган ыкмалар (create_table_robots.sql):
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;
Бул tableны көрсөткөн уюм:
@Builder
@Data
public class Robot {

   private Long id;

   private String name;

   private String cpu;

   private String producer;
}
Сыналган репозиторийдин интерфейси:
public interface RobotDAO {

   Robot findById(Long id);

   Robot create(Robot robot);

   List<Robot> findAll();

   Robot update(Robot robot);

   void delete(Long id);
}
Чындыгында, бул жерде экзотикасыз стандарттуу CRUD операциялары бар, ошондуктан биз бардык ыкмаларды эмес (жакшы, бул эч кимди таң калтырbyte) ишке ашырууну карап чыгабыз, бирок кээ бирлери - кыскараак:
@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();
   }
Келгиле, бир аз чегинип, көз карандылыктарыбыз менен эмне болуп жатканын карап көрөлү (колдонмонун демонстрацияланган бөлүгү үчүн колдонулгандар гана берилген):
<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 - MariaDb маалымат базасына көз карандылык 10 - SpringBoot менен туташуу үчүн көз карандылык 16 - Ломбок (менин оюмча, бул кандай lib экенин баары билет) 22 - сыноо үчүн стартер (бизге керектүү JUnit орнотулган) 28 - стартер springJdbc менен иштөө Келгиле, биздин сыноолор үчүн зарыл болгон буурчак менен жазгы контейнерди карап көрөлү (айрыкча, 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 - MariaDB жогорулатуунун негизги компоненти (Жазгы алHowтын негизиндеги тиркемелер үчүн) 10 - маалымат базасын аныктоо 12 - түзүлгөн маалымат базасынын атын коюу 17 - биздин ишибиз үчүн конфигурацияларды чыгаруу 19 - Builder үлгүсүн колдонуу менен маалымат базасын түзүү ( Үлгүгө жакшы сереп ) Акыр-аягы, ызы-чуу болуп жаткан нерсе JdbcTemplate төө буурчагы түзүлүп жаткан маалымат базасы менен байланышуу. Идея бизде Дао тесттери үчүн негизги класс болот, андан бардык Дао тест класстары мурасталат, анын милдеттерине төмөнкүлөр кирет:
  1. негизги маалымат базасында колдонулган кээ бир скрипттерди ишке киргизүү (tableларды түзүү, мамычаларды өзгөртүү жана башкалар үчүн сценарийлер);
  2. tableларды тесттик маалыматтар менен толтурган тест сценарийлерин ишке киргизүү;
  3. tableларды жок кылуу.
@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 - @SpringBootTest annotationсын колдонуу менен биз тест конфигурациясын орноттук 11 - бул ыкмада аргумент катары биз керектүү tableлардын аттарын өткөрүп беребиз жана ал жооптуу эмгекчи катары аларды биз үчүн жүктөйт (бул бизге мүмкүнчүлүк берет бул ыкманы жүрөгүбүз каалагандай кайра колдонуу үчүн) 21 - биз бул ыкманы тазалоо үчүн колдонобуз, тактап айтканда, бардык tableларды (жана алардын маалыматтарын) маалымат базасынан жок кылуу 27 - бул ыкмадагы аргумент тесттик маалыматтары бар скрипттердин аталыштарынын массивдери болуп саналат. ал белгилүү бир ыкманы сыноо үчүн жүктөлөт. Сыноо маалыматтары менен скриптибиз:
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')
Эми биз бүгүн эмне үчүн чогулду.

Дао тестирлөө классы

@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 - биз тесттерибиз үчүн негизги класстан мураска алабыз 4 - сыналган репозиторийибиз 7 - ар бир тесттин алдында иштей турган ыкма 8 - керектүү tableларды жүктөө үчүн ата-эне класстын ыкмасын колдонобуз 11 - биз даобузду инициализациялайбыз 15 - ыкма ал ар бир сыноодон кийин ишке киргизилет, биздин маалымат базабызды тазалайт ушул класстын сыноолорунун башталышы жана аягына байланыштуу annotationларды колдонуу. Мисалы, бул тестти бир кыйла тездетет, анткени tableлар ар бир жолу түзүлүп, толугу менен жок кылынышы керек жана класста бир жолу. Бирок биз андай кылбайбыз. Эмне үчүн, сен сурайсыңбы? Эгерде методдордун бири үстөлдүн структурасын өзгөртсөчы? Мисалы, бир тилкени жок кылыңыз. Бул учурда, калган ыкмалар иштебей калышы мүмкүн же күтүлгөндөй жооп бериши керек (мисалы, арткы тилкени түзүү). Бул бизге эч кандай пайдасыз сыноолордун бири-бирине керексиз байланышын (көз карандылыгын) берет деп моюнга алышыбыз керек. Бирок мен чегиндим, уланталы...

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 - tableны тесттик маалыматтар менен толтуруу 5 - бизге керектүү an objectтин идентификаторун алуу

Метод тестин жаңыртуу

@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 - tableны тесттик маалыматтар менен толтуруу 5 - жаңыланып жаткан an objectтин идентификаторун алуу 7 - жаңыланган an objectти куруу 14 - текшерorп жаткан ыкманы колдонуу 15 - текшерүү үчүн жаңыланган an objectти алуу 20...28 - алынган маалыматтарды салыштыруу күтүлгөндөр Жаңыртуу ыкмасын сыноо түзүүгө окшош. Жок дегенде мен үчүн. Элдештирүүлөрдү сиз каалагандай бура аласыз: эч качан өтө көп текшерүүлөр болушу мүмкүн эмес. Ошондой эле тесттер толук иштөөгө же мүчүлүштүктөрдүн жоктугуна кепилдик бербестигин белгилегим келет. Тесттер программанын иш жүзүндөгү натыйжасы (анын фрагменти) күтүлгөнгө дал келээрин гана камсыздайт. Бул учурда, тесттер жазылган бөлүктөр гана текшерилет.

Сабакты тесттерден баштайлы...

MySql - 7ди алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөөЖеңиш)) Чай кайнатып печенье алып кетели: биз татыктуубуз)) MySql - 8ди алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөө

пайдалуу шилтемелер

Окуп бүткөндөр үчүн, көңүл бурганыңыз үчүн рахмат жана... MySql - 9 алмаштыруу үчүн MariaDB аркылуу маалымат базасын интеграциялык тестирлөө

*жылдыздар согушунун эпикалык музыкасы*

Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION