对MySQL数据库进行数据库测试的实例教程

438 阅读8分钟

测试是其中的一项活动,如果不详尽的话,就不会对你的软件开发过程产生完整的影响。通常情况下,开发人员只关注系统的应用层(又称代码库)的测试,而忽略了数据层(数据库)的测试,而数据层与代码本身的测试同样重要。

什么是数据库测试?数据库测试主要是由构建SQL查询来断言和验证不同的数据库操作,结构和数据库所需的属性。这些可能包括验证模式,测试CRUD操作和事务,以确保数据库被正确设置以服务于应用程序。关于数据库测试的更多信息和执行策略,你可以查看我们的数据库测试介绍文章

在本教程中,你将学习并演示如何测试一个关系型MySQL数据库,然后着手建立一个持续集成管道,使测试过程自动化。

前提条件

要跟着学习,你将需要一些东西。

  1. JavaScript的基本知识
  2. 在您的系统上安装Node.js(版本>=12)
  3. 一个CircleCI账户
  4. 一个GitHub账户
  5. SQL的基本知识。

在安装和设置好所有这些之后,你就可以开始了。

获取一个远程MySQL实例

当运行数据库测试时,你要确保你不在生产数据库上运行这些测试。确保测试数据库与生产中的数据库完全相似。

对于本教程,你将需要一个远程MySQL数据库来运行测试。许多云供应商提供免费的MySQL数据库,你可以使用并在以后删除。你可以自由地从任何你喜欢的服务中获得你的MySQL数据库,只要你有连接的详细信息。

在本教程中,我使用的是Cloud Clusters的数据库。一旦你注册了,就导航到MySQL。对我们的项目来说,MySQL的快速计划应该足够好用。点击免费试用。使用默认设置,设置一个免费的MySQL数据库。我们将在下一节中使用数据库的详细信息。

注意

  • 如果你使用的服务没有在实例化时创建一个默认的表,请创建一个表。
  • 对于本教程,你可以使用MySQL 5.7或MySQL 8.0版本,以及latinutf8utf8mb4gbk 字符集。唯一的例外是MySQL 8.0版本中的utf8mb4 字符集,它会抛出一个错误。

你可以在GitHub上获得最终的项目代码。这里使用的MySQL实例是MySQL 5.7版本。名为circleci 的数据库使用utf8 字符集。

用Jest和MySQL SDK设置测试项目

一旦你设置了你的远程MySQL,你现在可以开始设置测试环境。不同的代码库有不同的测试运行器来执行测试。在本教程中,你将使用Jest测试框架和MySQL Node.js SDK来执行数据库测试,因为我们使用的是一个JavaScript项目。

通过创建一个文件夹并移动到其根部,启动一个新的Node.js项目。

mkdir relational-db-testing
cd relational-db-testing

然后,初始化一个Node.js项目,用这个命令搭建一个基本的package.json 文件。

npm init -y

接下来,将jest 作为开发依赖项安装。

npm install --save-dev jest

然后,安装mysql2faker 包,以连接到你的MySQL实例并生成假的测试数据。

npm install mysql2 faker

现在你已经安装了项目和所有的包,是时候开始写测试了。

使用CRUD测试的数据完整性

在本教程中,你将运行简单的CRUD(创建-读取-更新-删除)测试来验证CRUD操作中的数据完整性。

在项目的根部创建一个新文件users.test.js 。在这个文件中,你将通过添加用户、读取添加的用户、更新用户和删除用户数据来测试一个users 数据库表。

在该文件中添加以下代码。它包括测试CREATEREAD 操作的测试。

const { createPool } = require("mysql2/promise");
const faker = require("faker");

describe("Database Tests", () => {
  let connection;

  beforeEach(async () => {
    let createTableSQL =
      "CREATE TABLE `users` ( `id` INT(2) NOT NULL AUTO_INCREMENT , `name` VARCHAR(100) NOT NULL , `email` VARCHAR(50) NOT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB;";

    connection = await createPool({
      host: "YOUR_DB_HOST",
      user: "YOUR_DB_USER",
      password: "YOUR_DB_PASSWORD",
      port: YOUR_DB_PORT,
      database: "YOUR_DB_NAME"
    });
    console.log("Connected to database");

    await connection.query(createTableSQL);
  });

  it("Test CREATE and READ", async () => {
    try {
      const total_test_users = 3;
      let insertQueries = [];

      for (let i = 0; i < total_test_users; i++) {
        let insertSQL = `INSERT INTO users (id, name, email) VALUES (NULL, '${faker.name.findName()}', '${faker.internet.email()}');`;

        insertQueries.push(connection.query(insertSQL));
      }

      await Promise.all(insertQueries);

      const [rows, fields] = await connection.query("SELECT * FROM users");

      expect(rows.length).toBe(total_test_users);
    } catch (error) {
      console.log(error);
      let dropTableSQL = "DROP TABLE IF EXISTS `users`";
      await connection.query(dropTableSQL);
      await connection.end();
    }
  }, 60000);

  afterEach(async () => {
    let dropTableSQL = "DROP TABLE IF EXISTS `users`";
    await connection.query(dropTableSQL);
    await connection.end();
  });
});

这个测试

  • 建立一个与数据库实例的连接
  • beforeEach 函数调用中,它创建了一个users 表,其字段为id,name, andemail
  • afterEach 函数调用中,丢弃该表并结束连接。

丢弃表可以确保套件中的每个测试都有一个新的users 表的实例,以避免测试使用相同的共享数据。记住用你的远程MySQL数据库主机、用户、密码、端口和数据库名称分别替换YOUR_DB_HOST,YOUR_DB_USER,YOUR_DB_PASSWORD,YOUR_DB_PORT, 和YOUR_DB_NAME

Test CREATE and READ 测试案例中,faker 库被用来向users 表添加3个用户。然后对该表进行查询,以确保它包含刚刚添加的用户的确切数量。

要运行这个测试,请更新你的package.json 文件中的test 脚本。

....,
"scripts" : {
    "test" : "jest"
}

现在到你的终端,通过运行来运行测试。

npm run test

测试完成后,你的终端会显示以下输出。

> jest

  console.log
    Connected to database

      at Object.<anonymous> (users.test.js:18:17)

 PASS  ./users.test.js (5.5 s)
  Database Tests
    ✓ Test CREATE and READ (4292 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.554 s
Ran all test suites.

CREATEREAD 的测试通过了,这意味着可以通过简单的INSERT 查询对我们的模式和数据库进行这些操作。这可以进一步扩展,以检查重复的电子邮件或用户名等情况。

对于UPDATEDELETE 操作,继续添加以下测试案例,就在第一个测试的it 块下面。

it("Test UPDATE and DELETE", async () => {
  try {
    let name = "Test user";
    let email = "test@user.com";
    let nameUpdate = "My Test User";

    let insertSQL = `INSERT INTO users (id, name, email) VALUES (NULL, '${name}', '${email}');`;

    await connection.query(insertSQL);

    //Run and test update
    let updateSQL = `UPDATE users SET name='${nameUpdate}' WHERE email='${email}'`;
    await connection.query(updateSQL);

    const [rows, fields] = await connection.query("SELECT * FROM users");
    expect(rows[0].name).toBe(nameUpdate);

    //Run and test delete
    let deleteSQL = `DELETE FROM users WHERE email='${email}'`;
    await connection.query(deleteSQL);

    const [allrows] = await connection.query("SELECT * FROM users");
    expect(allrows.length).toBe(0);
  } catch (error) {
    console.log(error);
    let dropTableSQL = "DROP TABLE IF EXISTS `users`";
    await connection.query(dropTableSQL);
    await connection.end();
  }
}, 60000);

在这个测试中,UPDATE 操作是通过创建一个新的用户并更新该用户的name 字段来测试的。然后对表进行查询,以检查更新是否持续。

接下来,使用用户的电子邮件对用户的数据运行一个DELETE 操作。再次查询该表,以检查该用户是否不再存在。

保存这个文件并再次运行测试命令(npm run test)。这一次,你将在你的终端中看到这个输出。

> jest

  console.log
    Connected to database

      at Object.<anonymous> (users.test.js:18:17)

  console.log
    Connected to database

      at Object.<anonymous> (users.test.js:18:17)

 PASS  ./users.test.js (8.165 s)
  Database Tests
    ✓ Test CREATE and READ (3452 ms)
    ✓ Test UPDATE and DELETE (3205 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        8.226 s
Ran all test suites.

测试过程自动化

现在你的测试已经正确运行,是时候将测试过程自动化了。首先,你需要保存对测试文件的所有修改。

然后,使当前目录成为本地git仓库,并添加一个.gitignore 文件。运行这些命令。

git init
wget https://raw.githubusercontent.com/github/gitignore/master/Node.gitignore && mv Node.gitignore .gitignore

第二条命令复制GitHub的官方.gitignore 文件的内容,用于托管这里的JavaScript项目。

接下来,将项目推送到GitHub

到CircleCI仪表板上的Projects page ,添加项目。

Add Project - CircleCI

点击Set Up Project,开始设置该项目。在弹出的模版上点击跳过此步骤。我们将在本教程的后面手动添加我们的CircleCI配置。

Add Config - CircleCI

在设置页面,点击使用现有的配置,指示CircleCI,你将手动添加一个配置文件,而不是使用样本。接下来,你会被提示为管道下载一个配置文件或开始构建。

Build Prompt - CircleCI

点击开始构建。这次构建将失败,因为我们还没有设置我们的配置文件。这将是你的下一个步骤。

要添加你的持续集成管道脚本,回到你的项目。在项目文件夹的根部创建一个名为.circleci 的文件夹,并在其中添加一个名为config.yml 的文件。在config.yml ,输入这段代码。

version: 2.1
jobs:
  build:
    working_directory: ~/repo
    docker:
      - image: circleci/node:12
    steps:
      - checkout
      - run:
          name: Update NPM
          command: "sudo npm install -g npm"
      - restore_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
      - run:
          name: Install Dependencies
          command: npm install
      - save_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
          paths:
            - ./node_modules
      - run:
          name: Run tests
          command: npm run test

这个配置拉入适当的Node.js镜像,并在其中更新npm 。然后,依赖性被安装和缓存,以使后续构建更快。最后,通过使用npm run test 命令来运行测试。

提交项目的所有修改,并推送到你的远程GitHub仓库。这就触发了构建管道,应该是成功的。

Build Successful - CircleCI

点击构建,然后展开运行测试,查看测试细节。

Build Details - CircleCI

总结

在本教程中,你已经演示了如何测试一个关系型数据库(MySQL),以及如何使用CircleCI来自动化这一过程。如果测试不是你的团队的首要任务,请与他们分享本教程,让他们自己了解它是多么容易设置。数据是你将要开发的几乎每一个应用程序的核心。数据的故障、损坏或漏洞会导致用户对产品的可信度失去信心,并导致公司失去业务。在你的软件开发操作中,把数据库测试放在最优先的位置。

编码愉快!