Day 29 RSpec 里的 Factories 和 Fixtures

该文章同步发布於:我的部落格

测试有一个必要的条件就是要有资料来做测试,有三种方法可以 Rails 中产生测试资料。

  1. 手动
  2. Fixtures
  3. Factory-Bot

这三种方法都是可行的解决方案,我们可以一个一个来探讨一下。

手动建立资料

如果你测试的 Model 只有几个属性,而且没有关联的 Model,手动建立测试资料可以说是非常方便。

例如,假设我有一个 PaymentType Model,只有一个属性,名字。而且也可以很轻易的做出合法以及不合法的状态,很简单!

valid_payment_type = PaymentType.new(name: 'Visa')
invalid_payment_type = PaymentType.new(name: '')

接着,我们有一笔订单,它是由多的 LineItems 和 Payments 组成,每个都有一个 PaymentType。

order = Order.create!(
  line_items: [
    LineItem.create!(name: 'PS5', price: 15000)
  ],
  payments: [
    Payment.create!(
      amount: 15000,
      payment_method: PaymentType.create!(name: 'Visa')
    )
  ]
)

这样写起来其实超级烦的,我们不得不浪费一堆脑力,想一些不一定相关的细节。

如果我们想要测试的是,amount 等於 line_items 的总额时,order.balance 回传 0,该怎麽做?

接这就是 Factory 派上用场的时候了!

Factories

Factory 其实不是一个针对测试的概念,Factory Method 是一种设计模式,可以在 Gang of Four 这本书中找到,而这个模式恰好对测试的目的很有用。

Factory 的概念基本上是,你有一个方法或是函数,可以为你产生新的类别。

Gang of Four 这本书中,他用了一个例子,一个叫做 Creator 的工厂会根据不同的条件回传 MyProduct 或是 YourProduct 的实体。可以直接说 Creator.create(相关资料),就会自然回传适当的实体!

你也许会想这样的 Factory 有什麽用处,在测试的情况下,我们想要的 Factory 类型可能会有一点不同。我们关心的不是抽象的类别实体化。我们希望抽象出没意义的细节和繁琐的 Model Association

下面是一个例子,说明如果我们用一个 Factory,特别是 Factory-Bot,刚刚 Order 的设置会是怎麽样呢?( 关於 Factory-Bot 在之前的文章有做过分享基本的用法 )

order = create(
  :order,
  line_items: [create(:line_item, price: 15000)],
  payments: [create(:payment, amount: 15000)]
)

在这样的情况下,我们只需要专注在我们要测试的项目,不用像刚刚手动的那样关心一些奇怪的名目和支付方式,做好我们关心的 priceamount,就是我们最关心的一切。

那我们要怎麽用 fixtures 来实现同样的事情呢?

Fixtures

首先我自己对於 fixtures 的经验和 Factory-Bot 相比,比较不熟。但可以看看这篇关於 fixtures 的文章!

说到这里,如果我们想用做出和上面 Factory-Bot 一样的测试资料,也可以使用 fixtures 来做,通常情况下,我看别人都是用 YAML 档的形式来表达!

# orders.yml
payments_equal_line_item_total:
  # no attributes needed

# line_items.yml
ps5:
  order: payments_equal_line_item_total
  name: 'PS5'
  price: 15000

# payment_methods.yml
visa:
  name: 'Visa'

# payments.yml
first:
  order: payments_equal_line_item_total
  payment_method: visa
  amount: 15000

一但确定好 fixtures 的资料後,用它就像在用 Hash 的 key 一样简单~

order = orders(:payments_equal_line_item_total)

所以,你觉得哪一种生产测试资料的方式好用呢?

小结

我想前面已经证明,手动产生测试资料这件事情真的很容易就很麻烦,但是,也不是真的不好用,他其实在自己的 side project 里面就很好用,手动生产就不需要开档案,分那麽多的资料夹,而且可读性又提高,东西都在一个档案里面~

至於 fixtures 和 Factory-Bot,我自己是用 Factory 居多,主要原因是 Gem 的强大,还有 YAML 档,虽然很好读,但我自己还是不太习惯,可能这就是工具用久的依赖性吧~

至於之前看到有人提过关於 fixtures 的见解,他认为,一个专案会创造一个 资料世界,然後用这个很大又很复杂的世界作为测试的基础,发文的人说他更倾向於在可行的情况下,从一个乾净的 Model 开始每一个测试,并为每个测试产生该测试所需要的最低限度资料,他发现,这让测试变得容易理解,而不是用 fixtures 制造出一个固定的资料!

当然也不是说只能挑一个做使用,但如果今天你想要有一个固定的回传资料或是什麽的可以( 可能是金流,那种从来不会改变的东西 ),你也可以做一个 fixtures 然後传到 Factory,在整个测试基础上产生动态资料!

我自己还是大推 Factory-Bot 啦,但可能我自己对於 fixtures 的理解也不够深,说不定一年过後就会推翻这些自己觉得是对的东西,那也没关系啦,继续变强才是重点嘛~


<<:  30天学会C语言: Day 27-指标当参数

>>:  Day 28 加入 Action

Day 20 2D Arrays

在Java程序设计中,有时一维阵列无法计算较多且较复杂的,这时我们需要二维阵列,例如要产生一个阵列A...

Flutter体验 Day 21-Http

Http 使用 Http 通讯协定,发送网路请求存取网路上的资源在开发App是很基本的需求,今日我们...

[Day20] Flutter GetX routing

这篇主要讲GetX在页面切换之间的路由(上下页的前後文关系) 初步先建立一个routes的资料夹 里...

30天学会 Python: Day 29- 云端资料库

Firebase 云端服务平台之一,提供资料库、机器学习、虚拟机、登入验证等服务 建立专案 要使用 ...

laravel8 10分钟保证完成

软件版本 PHPphp7.3 WebServicenginx FRAMEWORKLaravel8 ...