资讯专栏INFORMATION COLUMN

写Laravel测试代码(二)

Jackwoo / 1305人阅读

摘要:本文主要探讨数据库测试。在写测试代码一中聊了关于如何提高数据库测试性能,其实简单一句就是每一个只重新被污染的表。最后还得在中创建用户并授权,以用户登录这样就临时测试数据库就准备完毕了,然后就是测试数据,执行,执行等等,可以参考写测试代码一。

本文主要探讨数据库测试。

在写Laravel测试代码(一) 中聊了关于如何提高 laravel 数据库测试性能,其实简单一句就是:每一个test case, 只重新 seed 被污染的表。 OK,这里有一个前提问题:那如何构建临时测试数据库呢?本文主要探讨如何构建临时测试数据库。

数据库设计图纸

任何一个软件都需要数据库设计图纸,可以使用免费的MySqlWorkbench或者收费的Navicat Data Modler软件。这里使用免费的MySqlWorkbench来设计数据库图纸,类似下图:

这里作为范例简单设计了5个model,当然大型程序都会有100个以上model。再利用软件的Export SQL功能导出数据库的schema,这个schema文件就作为构建临时测试数据库的原料,schema文件类似如下:

临时数据库构建类

在得到 schema 文件后,就可以写一个临时数据库构建类来创建临时测试数据库。这里临时表示该测试数据库使用完后即drop掉,且数据库名字是随机的,这样可以保证同时并发进行测试。需要先在phpunit.xml中指定数据库配置信息:

...
    
        
        
        
        
        
        
        
    

然后在config/database.php中写上当运行测试时指定新构建的测试数据库:

"mysql" => [
            "driver" => "mysql",
            "host" => env("DB_HOST", "127.0.0.1"),
            "port" => env("DB_PORT", "3306"),
            "database" => env("APP_ENV") === "testing" ? TestsDatabase::getRandomDBName(env("DB_DATABASE", "lx1036"), env("DB_HOST", "localhost"), env("DB_USERNAME", "root"), env("DB_PASSWORD")) : env("DB_DATABASE", "forge"),
            "username" => env("DB_USERNAME", "forge"),
            "password" => env("DB_PASSWORD", ""),
            "unix_socket" => env("DB_SOCKET", ""),
            "charset" => "utf8mb4",
            "collation" => "utf8mb4_unicode_ci",
            "prefix" => "",
            "strict" => true,
            "engine" => null,
        ],

然后写一个临时测试数据库构建类:

exec("DROP DATABASE `" . static::$db_name . "`");
        }
    }

    public static function getRandomDBName(string $prefix, string $host, string $username, string $password, string $charset = "utf8mb4", string $collation = "utf8mb4_unicode_ci"): string
    {
        if (static::$instance) {
            return static::$instance->getDBName();
        }

        $db_name = $prefix . "_" . date("ymd") . "_" . str_random();

        $pdo = new PDO("mysql:host=" . $host, $username, $password);

        // Remove orphan database
        static::removeOrphans($pdo, $prefix);

        // Create random database
        $pdo->exec("CREATE DATABASE `" . $db_name . "` DEFAULT CHARACTER SET " . $charset . " COLLATE " . $collation);
        $pdo->exec("USE `" . $db_name . "`");

        // Create tables in specified random database
        $schema_file = __DIR__ . "/../database/seeds/mysql.sql";

        if ($pdo->exec(file_get_contents($schema_file)) === false) {
            throw new ErrorException("Cannot create tables by sql file: " . $schema_file . " because of " . $pdo->errorInfo()[2]);
        }

        /*
        // Check if tables are inserted.
        $result = $pdo->query("SHOW TABLES")->fetchAll(PDO::FETCH_NUM);
        dump($result);*/

        static::$instance = new static($db_name);
        static::$host     = $host;
        static::$username = $username;
        static::$password = $password;

        dump($db_name);
        return $db_name;
    }

    /**
     * Remove orphan database if exists.
     *
     * @param PDO $pdo
     * @param string $prefix
     */
    public static function removeOrphans(PDO $pdo, string $prefix)
    {
        $databases = $pdo->query("SHOW DATABASES LIKE "" . $prefix . "%"")->fetchAll();

        foreach ($databases as $database) {
            $database = reset($database);

            if (starts_with($database, $prefix) && is_numeric(explode("_", $database)[1])) {
                $pdo->exec("DROP DATABASE `" . $database . "`");

                echo "Drop database " . $database . PHP_EOL;
            }
        }
    }

    /**
     * @return string
     */
    public static function getDBName(): string
    {
        return static::$db_name;
    }

    /**
     * @return string
     */
    public static function getHost(): string
    {
        return static::$host;
    }

    /**
     * @return string
     */
    public static function getUsername(): string
    {
        return static::$username;
    }

    /**
     * @return string
     */
    public static function getPassword(): string
    {
        return static::$password;
    }
}

这样,当运行测试时连接的就是临时构建的测试数据库,测试运行完毕就drop掉数据库,并且可以同时开多个窗口(线程)来分组运行test cases。最后还得在mysql localhost中创建testing@testing用户并授权,以root用户登录local mysql

CREATE USER "testing"@"localhost" IDENTIFIED BY "testing";
GRANT ALL ON `lx1036%`.* TO "testing"@"localhost";

这样就临时测试数据库就准备完毕了,然后就是seed 测试数据,执行unit/feature tests, 执行assert等等,可以参考写Laravel测试代码(一)。这里运行phpunit时得到的临时测试数据库是:

OK,后续再聊执行unit/feature tests时一些实践技巧。

RightCapital招聘Laravel DevOps

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/23340.html

相关文章

  • Laravel 菜鸟晋级之路

    摘要:用也有三四个月了,虽然是兼职开发,但是使用的频率非常之高,毕竟是产品化的一个项目。第二阶段数据库和开发了比较多的功能之后,会发现需要大量的测试数据,这时候和就该大显身手了。 用Laravel也有三四个月了,虽然是兼职开发,但是使用的频率非常之高,毕竟是产品化的一个项目。在这期间,也踩了无数的坑,走了很多弯路,所以准备把最近的感悟记录下来,方便后来者。 第一阶段:简单的增删改查 这是最...

    YacaToy 评论0 收藏0
  • laravel认识之 路由控制() csrf 白名单设置

    摘要:之前简单的做了的传递参数,可能只是大多数中的一种吧,这里做一个请求的实例默认开启了防护功能当然也可以关闭这个功能,设置的文件路径如下注释掉的就关闭了全局的防护,但是一般不会这么做。 之前简单的做了url的get 传递参数,可能只是 大多数中的一种吧,这里做一个 post 请求的实例,laravel默认开启了csrf 防护功能,当然也可以关闭这个功能,设置的文件路径 app/Http/K...

    springDevBird 评论0 收藏0
  • 打造你的Laravel即时应用()-消息推送与监听

    摘要:打造你的即时应用二消息推送与监听年月日接于上篇博客打造你的即时应用一项目初始化构建在上一篇博客中介绍了项目的基本构建现在进入实战操作一消息推送创建事件类的广播推送通过来实现下面通过命令来创建一个事件类为了配合我们的广播系统使用需要实现接 打造你的Laravel即时应用(二)-消息推送与监听 2019年08月04日20:16:21 XXM 接于上篇博客: 打造你的Laravel即时应用(...

    omgdog 评论0 收藏0
  • LaravelLaravel 框架关键技术解析·读书笔记(

    摘要:框架关键技术解析读书笔记二第五章框架应用程序根目录版本默认的框架应用程序是符合规范的,所以相应的目录结构也是基本固定的,不同的目录加载了功能文件,如果添加了新的目录,需要在文件中添加规范的自动加载部分并执行命令。 Laravel 框架关键技术解析·读书笔记(二) 第五章 框架应用程序根目录(5.1版本) 默认的Laravel框架应用程序是符合PSR规范的,所以相应的目录结构也是基本...

    TIGERB 评论0 收藏0
  • laravel5.4发送邮箱

    摘要:一发送邮箱其实不难,不如说挺简单的,首先还是现在注册一个账号并且设置如下图授权码很重要的,请好好记住,待会在的中要配置到的二如果以上你都做完了,那接下来就是配置了你的账号你的客户端授权密码你的账号账号名三然后接下来就是配置路由以及在控制器上 一、发送邮箱其实不难,不如说挺简单的,首先还是现在163注册一个账号并且设置如下图 showImg(https://segmentfault.c...

    ZHAO_ 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<