JavaRush /จาวาบล็อก /Random-TH /การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql
Константин
ระดับ

การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql

เผยแพร่ในกลุ่ม
การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql - 1วันนี้ผมอยากจะพูดถึงการทดสอบ เพราะยิ่งโค้ดครอบคลุมการทดสอบมากเท่าไรก็ยิ่งถือว่าดีและเชื่อถือได้มากขึ้นเท่านั้น เราจะไม่พูดถึงการทดสอบหน่วย แต่เกี่ยวกับการทดสอบการรวมฐานข้อมูล ความแตกต่างระหว่างการทดสอบหน่วยและการทดสอบการรวมคืออะไร? การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql - 2โมดูลาร์ (หน่วย) คือการทดสอบโปรแกรมในระดับของแต่ละโมดูล วิธีการ หรือคลาส กล่าวคือ การทดสอบนั้นรวดเร็วและง่ายดาย ซึ่งส่งผลต่อส่วนที่แบ่งแยกได้มากที่สุดของฟังก์ชันการทำงาน เรียกอีกอย่างว่า "การทดสอบหนึ่งรายการต่อวิธี" การบูรณาการจะช้ากว่าและหนักกว่า และอาจประกอบด้วยหลายโมดูลและฟังก์ชันเพิ่มเติม การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql - 3เหตุใดการทดสอบสำหรับการทดสอบการรวมเลเยอร์ dao (Data Access Object) จึงเป็นเช่นนั้น เนื่องจากในการทดสอบวิธีที่มีการสืบค้นไปยังฐานข้อมูล เราจำเป็นต้องสร้างฐานข้อมูลแยกต่างหากใน RAM โดยแทนที่ฐานข้อมูลหลัก แนวคิดก็คือเราสร้างตารางที่เราต้องการ กรอกข้อมูลการทดสอบและตรวจสอบความถูกต้องของวิธีการคลาสพื้นที่เก็บข้อมูล (ท้ายที่สุดแล้ว เรารู้ว่าผลลัพธ์สุดท้ายควรเป็นอย่างไรในกรณีที่กำหนด) เอาล่ะ มาเริ่มกันเลย หัวข้อเกี่ยวกับการเชื่อมต่อฐานข้อมูลได้รับการกล่าวถึงมานานแล้วดังนั้นวันนี้ฉันไม่อยากพูดถึงเรื่องนี้และเราจะพิจารณาเฉพาะส่วนของโปรแกรมที่เราสนใจเท่านั้น ตามค่าเริ่มต้น เราจะเริ่มจากข้อเท็จจริงที่ว่าแอปพลิเคชันของเราใช้ Spring Boot สำหรับเลเยอร์ Spring JDBC dao (เพื่อความชัดเจนยิ่งขึ้น) ฐานข้อมูลหลักของเราคือ MySQL และเราจะแทนที่โดยใช้ MariaDB (เข้ากันได้สูงสุด และ ดังนั้นสคริปต์ MySQL จะไม่ไม่มีความขัดแย้งกับภาษา MariaDB เนื่องจากจะมีกับ H2) นอกจากนี้เรายังจะถือว่ามีเงื่อนไขว่าโปรแกรมของเราใช้ Liquibase เพื่อจัดการและใช้การเปลี่ยนแปลงกับสคีมาฐานข้อมูล ดังนั้นสคริปต์ที่ใช้ทั้งหมดจะถูกเก็บไว้ในแอปพลิเคชันของเรา

โครงสร้างโครงการ

แสดงเฉพาะส่วนที่ได้รับผลกระทบ: การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql - 5และใช่ วันนี้เราจะสร้างโรบอต)) การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql - 6สคริปต์สำหรับตาราง วิธีที่เราจะทดสอบวันนี้ (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;
เอนทิตีที่เป็นตัวแทนของตารางนี้:
@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 มาตรฐานโดยไม่มีสิ่งแปลกใหม่ ดังนั้นเราจะพิจารณาการใช้งานไม่ใช่ทุกวิธี (ซึ่งจะไม่ทำให้ใครแปลกใจ) แต่บางวิธี - เพื่อความกระชับยิ่งขึ้น:
@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 มาดู Spring Container พร้อมถั่วที่จำเป็นสำหรับการทดสอบของเรากัน (โดยเฉพาะ MariaDB Creation Bean):
@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 (สำหรับแอปพลิเคชันที่ใช้ Spring Framework) 10 - การกำหนด bean ฐานข้อมูล 12 - การตั้งชื่อฐานข้อมูลที่สร้างขึ้น 17 - ดึงการกำหนดค่าสำหรับกรณีของเราออกมา 19 - การสร้างฐานข้อมูลโดยใช้รูปแบบ Builder ( ภาพรวมที่ดีของรูปแบบ ) และสุดท้าย สิ่งที่ยุ่งยากทั้งหมดคือ JdbcTemplate bean สำหรับการสื่อสารกับฐานข้อมูลที่กำลังถูกยกขึ้น แนวคิดก็คือ เราจะมีคลาสหลักสำหรับการทดสอบ Tao ซึ่งคลาสการทดสอบ Dao ทั้งหมดจะสืบทอดมา ซึ่งมีงานดังนี้:
  1. การเรียกใช้สคริปต์บางตัวที่ใช้ในฐานข้อมูลหลัก (สคริปต์สำหรับสร้างตาราง การเปลี่ยนคอลัมน์ และอื่นๆ)
  2. การเปิดตัวสคริปต์ทดสอบที่เติมตารางด้วยข้อมูลการทดสอบ
  3. กำลังลบตาราง
@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 เราตั้งค่าการกำหนดค่าการทดสอบ 11 - เป็นอาร์กิวเมนต์ในวิธีนี้เราส่งชื่อของตารางที่เราต้องการ และเขาในฐานะผู้ทำงานหนักที่มีความรับผิดชอบจะโหลดตารางเหล่านั้นให้เรา (ซึ่งทำให้เรามีโอกาส เพื่อนำวิธีนี้กลับมาใช้ใหม่ได้มากเท่าที่ใจเราต้องการ) 21 - เราใช้วิธีนี้ในการทำความสะอาด ได้แก่ การลบตารางทั้งหมด (และข้อมูล) ออกจากฐานข้อมูล 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 - เราใช้วิธีคลาสหลักเพื่อโหลดตารางที่จำเป็น 11 - เราเริ่มต้น dao 15 ของเรา - วิธีการ ที่จะเปิดตัวหลังการทดสอบแต่ละครั้ง การล้างฐานข้อมูลของเรา 19 - การใช้งาน RowMapper ของเรา ซึ่งคล้ายคลึงกับคลาส Tao เราใช้ @Before และ @After ซึ่งใช้ก่อนและหลังวิธีทดสอบวิธีหนึ่ง แต่เราสามารถนำ lib บางส่วนที่ช่วยให้เรา เพื่อใช้คำอธิบายประกอบที่เชื่อมโยงกับจุดเริ่มต้นของการทดสอบการดำเนินการของคลาสนี้และจุดสิ้นสุด ตัวอย่างเช่นอันนี้ซึ่งจะเร่งการทดสอบได้อย่างมาก เนื่องจากจะต้องสร้างและลบตารางทั้งหมดทุกครั้ง และหนึ่งครั้งต่อชั้นเรียน แต่เราไม่ทำอย่างนั้น คุณถามทำไม? จะเกิดอะไรขึ้นหากวิธีใดวิธีหนึ่งเปลี่ยนโครงสร้างของตาราง? ตัวอย่างเช่น ลบหนึ่งคอลัมน์ ในกรณีนี้ วิธีการที่เหลืออาจล้มเหลวหรือต้องตอบสนองอย่างเหมาะสม (เช่น สร้างคอลัมน์ด้านหลัง) เราต้องยอมรับว่าสิ่งนี้ทำให้เราเชื่อมโยงกันโดยไม่จำเป็น (การพึ่งพา) การทดสอบซึ่งกันและกัน ซึ่งไม่มีประโยชน์สำหรับเรา แต่ฉันเชือนแชไปดำเนินการต่อ ...

ทดสอบเมธอด 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 - กรอกข้อมูลการทดสอบลงในตาราง 5 - รับรหัสสำหรับเอนทิตีที่เราต้องการ 6 - ใช้วิธีการทดสอบ 8...12 - เปรียบเทียบข้อมูลที่ได้รับกับข้อมูลที่คาดหวัง

อัปเดตวิธีทดสอบ

@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 - กรอกตารางด้วยข้อมูลการทดสอบ 5 - รับรหัสของเอนทิตีที่กำลังอัปเดต 7 - สร้างเอนทิตีที่อัปเดต 14 - ใช้วิธีการทดสอบ 15 - รับเอนทิตีที่อัปเดตสำหรับการตรวจสอบ 20...28 - เปรียบเทียบข้อมูลที่ได้รับกับ สิ่งที่คาดหวัง การทดสอบวิธีการอัพเดตนั้นคล้ายกับการสร้าง อย่างน้อยสำหรับฉัน คุณสามารถบิดการกระทบยอดได้มากเท่าที่คุณต้องการ โดยจะต้องไม่มีเช็คมากเกินไป ฉันอยากจะทราบด้วยว่าการทดสอบไม่รับประกันการทำงานเต็มรูปแบบหรือไม่มีข้อบกพร่อง การทดสอบทำให้แน่ใจได้ว่าผลลัพธ์ที่แท้จริงของโปรแกรม (แฟรกเมนต์ของโปรแกรม) สอดคล้องกับผลลัพธ์ที่คาดไว้เท่านั้น ในกรณีนี้จะมีการตรวจสอบเฉพาะส่วนที่เขียนการทดสอบเท่านั้น

มาเปิดคลาสแบบทดสอบกันดีกว่า...

การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql - 7ชัยชนะ)) ไปชงชาและรับคุกกี้กันเถอะ: เราสมควรได้รับมัน)) การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql - 8

ลิงค์ที่เป็นประโยชน์

สำหรับผู้ที่อ่านจบแล้ว ขอขอบคุณที่ให้ความสนใจและ... การทดสอบการรวมฐานข้อมูลโดยใช้ MariaDB เพื่อแทนที่ MySql - 9

*เพลง Star Wars อันยิ่งใหญ่*

ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION