laravel进行单元测试的时候如何模拟数据库以及mockery的调用

时间:2023-03-08 18:06:06

单元测试是独立的,所谓的独立是指有独立的运行容器,独立的数据库。

这样做有什么好处呢?

(1). 不会跟正常的容器产生冲突,继而影响正常业务。

(2). 数据库独立防止数据被修改影响单元测试结果。

这两天攻克了单元测试的两个问题:模拟数据库、mockery的调用。现在把原理解析一下。

1. 模拟数据库

那这样,我们来想一下。正常的创建一个数据库要有那些流程?

(1)定义表结构

(2)往表中插入数据

其实测试使用的模拟数据库总的来说也就这两个流程。

来来来,敲黑板,重点来了。

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

database目录下有三个文件夹,migrations中存储的是表结构文件,factories中存储的是创建模拟数据的方法,seeds没研究,暂时不知道干啥用的。

这个时候可能会有人问:创建表结构文件是什么鸡儿?它有啥用啊。

我们这样想一下:我们要创建模拟数据库,那数据库中肯定要有表吧。表长什么样子呢?你不给定义laravel怎么知道呢?那在哪里定义呢?就在migrations下面定义!!!

来给大家举个例子:

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

看见这个文件没?它就是定义表结构的地方。它长这个样子:

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

我们再仔细看看这个文件名:

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

哇,这名字这么长。还有日期,中间还有一串数字,让我怎么写嘛。

兄弟,别急。我有一计可保你平安。

在项目下面执行这句话:你就会得到你想要的结果

php artisan make:migration test --path=database/migrations/pandaRead

look here:

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

创建了新的文件,有木有,有木有。然后你就可以在up中写你表结构的定义了。

有同学可能会问这表里面的东西都是干啥的呀?作者云:内事不决问百度,外事不决问谷歌。

知道了为啥定义表结构和怎么设定表结构。

这个时候可能又会有兄弟问了:唉,你这个migrations下面为啥还有个pandaRead目录啊?你创建它干啥啊?

问的好!!!

一个大型的项目它所涉及到的数据库往往不止一个,而且各个数据库涉及到的业务往往不交叉,所以我们往往只会模拟一个数据库中的所有表。如果一次性的把所有数据库中的所有表都创建了,会很浪费资源。因此:给每个库定义一个文件夹,文件夹下面存储某个库下面的表结构文件,这样你在加载数据的时候可以根据文件夹把涉及到的所有表都一下子给创建了。

那又会有同学问了,什么时候创建表呢?表创建在哪里呢?

我就喜欢你这样问题多的小朋友!!!

来来来,诸位看官且把目光移到这里。

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

看到TestCase这个类了吗?它将会是你创建的所有测试文件的父类!!

那举个例子:

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

看到了没,所有的类都继承了TestCase这个类。

那我们是不是可以想:既然所有的类都继承了TestCase这个类,那我们的配置是不是可以写到TestCase这里呢?当然可以!!!

等等???什么配置,我还没反应过来怎么就讲到配置了呢?

小老弟,别急。来来来,看这里,思考这几个问题:

(1)我们的表创建在哪里呢?创建到文件里?数据库里?还是内存里?我们要在哪里告诉系统呢?

(2)刚才我们定义了表结构文件,但是定义了并没有加载啊。在哪里加载他们呢?

想明白了吗?这些东西我们都要告诉laravel,不然即使laravel再强大,它也无能为力啊!!!

那在哪里告诉它呢?敲黑板,敲黑板,重点来了哈。

我们来看看TestCase.php这个类中到底有什么东西。

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

创建表的地方,数据库连接的方式都在这里配置。

创建表没什么好讲的了,我们来讲讲数据库的连接方式:

config(['database.connections.mysql' => config('database.connections.testing')]);

这句话其实就是给数据库添加配置:在database配置文件中,connections.mysql的配置

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

这样数据库的配置就搞定了。

别急我们再看下这个方法,一层一层的剥离下去,我们看看它到底做了什么

parent::setUp();

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

最终其实它创建了一个新的容器。

优秀啊,优秀啊!!!这样你每执行一个单元测试的时候,都会创建一个新的容器,各个文件的单元测试之间就不会相互影响了。厉害啊

现在我们再来看看模拟数据:

这个时候可能会有人问:什么是模拟数据啊?你想啊,你测试是不是需要数据?数据谁来创建?你可以选择自己创建,同时你也可以选择交给机器去创建,那你要创建什么样的数据呢?在哪里定义呢?你创建一条数据可以自己创建,创建10条也可以自己创建,那你要创建1000条,10000条呢?还自己创建吗?这个时候你就需要机器来帮你做这件事情了!!

没错。就是在这里定义。举个例子:

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

它里面是长这个样子的。里面的数据根据你的需要自己配置。Generator可是很强大的啊啊啊啊啊啊!!!建议大家看看

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

诺,看见了没?给那个类创建什么数据都在这里面定义好了。那什么时候插入呢?

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

看见没,我们可以直接用工厂创建,然后最后可以直接插入到数据表中!!!读取数据的方式就和平时读取数据的方式一样,没什么区别了。

2. mockery

模拟数据库讲清楚了,那mockery呢?

什么叫mockery,什么时候用到mockery呢?

mockery......自己去查吧。

简单的说你可以将mock理解为替换掉类中的某个方法,或者替换掉某个类。

看这里,我们mock掉了一个类的某个方法,然后重新在容器中绑定这个类,这样容器中的类就被替换了,当我们测试的时候调用这个类的这个方法的时候,就直接按照我们mock的数据返回了,优秀啊!!!

laravel进行单元测试的时候如何模拟数据库以及mockery的调用

本次分享,到这里就结束了,欢迎大家批评指正。