RSpec 测试示例与技巧说明

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

目录

  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 中常用的测试技巧,包括基本断言、异常处理、状态变化、依赖注入、使用 spydouble 进行测试,以及模拟日期和时间。这些技巧可以帮助你编写更高效、更可靠的测试代码。