RSpec 测试示例与技巧说明

本文档整理了多个 RSpec 测试示例,并详细说明了每个示例中使用的技巧和代码示例。这些示例涵盖了常见的测试场景,包括基本断言、异常处理、状态变化、依赖注入、以及使用 spy 和 double 进行测试。

目录

  1. 基本断言
  2. 异常处理
  3. 状态变化
  4. 依赖注入与 double
  5. 使用 spy 进行测试
  6. 模拟日期和时间

基本断言

示例代码

RSpec.describe 'Assertion' do
  describe 'expect equality' do
    it do
      foo = 1
      expect(foo).to eq(1)
    end

    it do
      foo = [1, 2, 3]
      expect(foo).not_to equal([1, 2, 3])
    end
  end

  describe 'expect Truthiness' do
    it { expect(1 + 1 == 2).to be true }
  end

  describe 'match array' do
    it do
      arr = [1, 2, 3]
      expect(arr).to match_array([1, 2, 3])
    end
  end
end

技巧说明

  • eq 断言:用于检查两个对象的值是否相等。
  • equal 断言:用于检查两个对象是否是同一个对象(即内存地址相同)。
  • be true 断言:用于检查表达式是否为 true。
  • match_array 断言:用于检查数组是否包含相同的元素,忽略顺序。

异常处理

示例代码

RSpec.describe 'Assertion' do
  describe 'exception' do
    it do
      expect { nil.split(',') }.to raise_error(NoMethodError)
    end
  end
end

技巧说明

  • raise_error 断言:用于检查代码块是否抛出了指定的异常。

状态变化

示例代码

RSpec.describe 'Assertion' do
  describe 'state change' do
    it do
      arr = [1]
      expect { arr += [2, 3] }.to change { arr.size }.by(2)
    end
  end
end

技巧说明

  • change 断言:用于检查代码块执行前后某个状态的变化。by(2) 表示状态变化了 2。

依赖注入与 double

示例代码

RSpec.describe Order do
  describe 'create new order' do
    context 'when inventory is enough' do
      it 'order is valid' do
        warehouse = double('warehouse')
        expect(warehouse).to receive(:has_enough?).with(50).and_return(true)
        expect(warehouse).to receive(:remove).with(50)

        order = Order.new(warehouse, 50)

        expect(order.valid?).to be true
      end
    end

    context 'when inventory is not enough' do
      it 'order is invalid' do
        warehouse = double('warehouse')
        expect(warehouse).to receive(:has_enough?).with(51).and_return(false)

        order = Order.new(warehouse, 51)

        expect(order.valid?).to be false
      end
    end
  end
end

技巧说明

  • **double**:用于创建一个模拟对象,可以定义该对象的行为和返回值。
  • **receive**:用于模拟对象的方法调用,并指定返回值。

使用 spy 进行测试

示例代码

RSpec.describe MyHelper do
  describe '#average_of' do
    it 'use reduce to sum' do
      arr_spy = spy([1, 2, 3])
      average_of(arr_spy)

      expect(arr_spy).to have_received(:reduce)
    end
  end
end

技巧说明

  • **spy**:用于创建一个间谍对象,可以记录对象的方法调用情况。
  • **have_received**:用于检查间谍对象是否接收到了指定的方法调用。

模拟日期和时间

示例代码

RSpec.describe Calendar do
  describe '.today_day_off?' do
    context 'when today is sunday' do
      before do
        allow(Date).to receive(:today).and_return(Date.parse('2017-07-23'))
      end

      it 'return true' do
        expect(Calendar.new.today_day_off?).to be true
      end
    end

    context 'when today is monday' do
      before do
        allow(Date).to receive(:today).and_return(Date.parse('2017-07-24'))
      end

      it 'return false' do
        expect(Calendar.new.today_day_off?).to be false
      end
    end
  end
end

技巧说明

  • **allow**:用于模拟类或对象的方法调用,并指定返回值。
  • **and_return**:用于指定模拟方法的返回值。

通过这些示例,你可以掌握 RSpec 中常用的测试技巧,包括基本断言、异常处理、状态变化、依赖注入、使用 spy 和 double 进行测试,以及模拟日期和时间。这些技巧可以帮助你编写更高效、更可靠的测试代码。