Day 13 懒得想变数吗? RSpec 有提供你啦

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

还记得我们使用 let 方法来实作一个物件来让我们可以快速使用!

但有没有什麽好方法可以让我不要想物件的名字?可能因为我有取名的障碍或是英文真的太烂了!

甚至我连 let 都懒得写,我实在是太懒惰了...

有! RSpec 有个有趣的方法叫做 subject,他会自动根据整个 RSpec 最上层的描述来决定 subject 该是什麽!

Subject

刚刚的说法也都比不过一个实际的例子来得实际,看看以下范例!

RSpec.describe Hash do
  it "should be empty" do
    expect(subject.length).to eq(0)
  end
end

这是 OutPut 的结果:

现在一定是一头雾水,想说这个 subject 到底是在哪里?我们甚至没有宣告他啊?

这就是 RSpec 提供你的小方法喔,如果你的最上层 RSpec.describe 後方接的是类别,那 subject 就会依照这个类别的预设值去做 new 的动作。

我们可以把 subject 给印出来看看!

RSpec.describe Hash do
  it "should be empty" do
    p subject
    p subject.class
    expect(subject.length).to eq(0)
  end
end

OutPut 的结果:

所以我们可以想像,他在上方帮我们做了:

let(:subject) { Hash.new }

这是动态产生的,根据我们提供的类别来建立物件!是不是很方便呢?

加上他和 let 一样,在每一个 example 中都是独立的,不会有污染物件的情形,可以放心的服用!

加入初始值的 Subject

刚刚示范的是完全乾净的一个物件,但如果我们想要建立一个有不一样初始值的 subject 该怎麽做呢?

马上来示范一下:

RSpec.describe Hash do
  subject do 
    {a: 3, b: 4}
  end
  
  it "should be empty" do
    expect(subject.length).to eq(2)
  end
end

其实很简当,但如果我们不想要叫做 subject 呢?

只要在後面加入变数的命名就可以了喔!

RSpec.describe Hash do
  subject(:robert) do
    {a: 3, b: 4}
    
  end
  it "should be empty" do
    expect(subject.length).to eq(2)
    expect(robert.length).to eq(2)
  end
end

至於为什麽要这样用?我使用 let 还不是一样,何必浪费时间写三行呢?

你说的没错,用 let 的效果也是一样,但 subject 有其他更魔法的方法可以使用,等等也会一并介绍,会让写出来的 Code 优雅到不行!

在介绍黑魔法的写法之前,我先来介绍另一个也很有趣的语法。

Described_class

刚刚介绍的是 subejct 的好用之处,这次介绍的 described_class 可能不一定会用到,但在改大量程序码的时候很有效果!

我先用范例来解说一下:

class Burger
  attr_accessor :beef, :cheese
  
  def initialize(beef, cheese)
    @beef = beef
    @cheese = cheese
  end
end

RSpec.describe Burger do
  subject { Burger.new("Beef", "Cheedar") }
  let(:pork_burger) { Burger.new("Pork", "Cheedar") }
  
  it "...." do
    ....
  end
end

这边我们有个汉堡的类别,假设需求今天下来是要更改这个 Burger 类别的名称,怎麽办?

任务是把 Burger 改成 GoodBurger 这个名字,若是只有两三行,那倒是没什麽问题,但如果是 100 行呢? 我们要怎麽做?

这时候 described_class 就可以派上用场,若是我们都用这样的写法:

class GoodBurger
  attr_accessor :beef, :cheese
  
  def initialize(beef, cheese)
    @beef = beef
    @cheese = cheese
  end
end

# 我们只需要更改这边的类别名称就可以了!
RSpec.describe GoodBurger do
  subject { described_class.new("Beef", "Cheedar") }
  let(:pork_burger) { described_class.new("Pork", "Cheedar") }
  
  it "...." do
    ....
  end
end

described_class 虽然不是一个很常使用的东西,但他就是可以根据你上面放置的类别来动态产生物件,而且只需要改类别名称就能够一次跟上!

说不定在某些时候会帮助到你~

我只要写一行!

前面有提到使用 subject 的小小好处,就是可以让你只要写一行!

直接先看程序码:

RSpec.describe 5 do
  it "should be 5" do
    expect(subject).to eq(5)
  end

  context "one line syntax" do
    it { is_expected.to eq(5) }
  end
end

这是 OutPut

第三行是我们很常使用的写法,所以没有什麽问题。

但第七行就是 subject 的神奇之处, is_expected 这个方法本身的主词就是 subject,所以可以这样子就写完范例。

不觉得看起来整个就超级 Ruby Style 的,该省的都要给我省下来,越短越好!

希望这可以让你在写某些简单的 example 中可以派上用场!

Don't Repeat Yourself 能不要重复撰写就尽量节省!

小结

今天介绍了 subject & described_class 还有一行流的写法!

不一定是常常会使用到,但都是 RSpec 很基础的语法,至少先记在脑袋里面,想起来再去查资料就可以了!

现在介绍的都是整理单个测试的程序码,若是我们在不同的测试有着相同的 example 呢?


<<:  再谈 Side project

>>:  Day 27 - ios 开发实作(今天还要继续吃吗APP-1、Swift UI Passing data 不同页面传值)

[Day 28] Partitioning (2) - Partitioning and Secondary Indexes

Partitioning and Secondary Indexes 昨天谈了 key-value ...

练功活动: 模拟案主!!

在学习前端的过程,有做过真实需求的网站,会是珍贵的经验。而并不是时时刻刻都会有充足的案子,带每一个...

C# 入门之类(Class)

在前面介绍 C# 代码结构的时候,我们有提高过一下类(class),下面我们来看一下,如何定义一个类...

【Day 23】 AWS Kinesis - Data Streams vs Data Firehose 两者差异

前几天我们已经启用 VPC Flow Log、CloudFront Log,接下来我们就是要来实作 ...

Day7. 依点成形,创造物件 - RigidBody(中)

暨昨天介绍了物体的基本建立,我们今天来到中篇,没错,中篇後面还会有一个下篇,因为笔者写着写着发现篇幅...