Laravel的工厂在编写测试时节省了大量时间。过去,我构建一个工厂来包含默认状态下每个模型属性,但最近我改为默认使用极简工厂。我将解释这一变化的原因以及发现的益处。
让我们考虑一个具体的例子:一个UserProfile
模型。它有一个外键user_id
,两个非空属性,以及十多个可选属性,如bio
、profile_image
等。当我提到一个极简默认工厂时,我的意思是它只定义了成功保存到数据库所需的属性。所以,在这个UserProfile
工厂中,我会在默认工厂状态中只定义user_id
和两个非空属性。
然后,我创建额外的设置可选字段的状态。例如,我可能定义一个hasImage()
状态来设置profile_image
字段,并定义一个hasBio()
状态来设置bio
字段。我还可以定义一个fullProfile
状态,它将这些单个辅助工具组合起来,填充这个模型上的每一个可能字段。然后,如果需要额外的字段或一个完整的配置文件,我仍然可以使用工厂来节省时间。(顺便提一下,这也是我极其热爱 Laravel 8 中改为基于类的工厂的一个原因。它使得共享逻辑和构建更具表达性的工厂变得容易得多。)
那么,我为什么要做这个改动?我找到了哪些好处?我认为最大的好处就是测试的可读性大大提高。只需通过查看我的测试方法中的工厂方法链,就能看到我正在创建的模型的键特性,这在浏览测试套件并试图快速理解它时非常有用。
谈到测试中可读的工厂,如果一个模型有不同的状态影响业务逻辑,我通常只为可读性创建一个不改变默认状态的名字状态。例如,如果一个地址有一个
type
属性,可以是home
、work
或other
,并且默认状态将其设置为home
,我还会创建一个不进行任何更改的home()
状态,这样我就可以清楚地在我的测试中看到这是一个家庭地址。这并不总是很有用,但当默认状态影响业务逻辑时,我觉得在测试中明确这一点是非常有用的。
另一个额外的好处是它可以稍微加快你的测试速度。在我的UserProfile
例子中,为什么让Faker生成几段文本,然后再让我的数据库持久化所有这些数据,而这对测试逻辑完全没有影响呢?是的,我必须承认这可以被忽略为“微优化”,但当我看到测试套件逐渐增长时,我发现这个好处相当明显。
这种性能节省对可选关系来说尤其适用。比如说,你的应用程序允许用户进行支付。而不是让你的UserFactory
生成几个随机支付,我会将这委托给测试方法。我甚至不会把它作为一个状态添加到UserFactory
。相反,如果某个测试方法需要用户有支付,它应该负责调用PaymentFactory
来生成这些支付。
driesvints, ash-jc-allen 喜欢这篇文章