Rails 使用 MiniTest 测试服务对象

Rails test service object with MiniTest

我正在尝试了解 Rails 6 中的 MiniTest 以使用它而不是 RSpec。实际上,我发现的所有材料都与两件事有关:控制器和模型测试,它们不会触及像服务对象这样重要的东西。我有下面的服务对象,它只更新三个用户字段 - 状态、status_updated_at 和 failed_attempts。为了简化示例,我将省略其余条件。

  class FailedAttributes
    def initialize(user)
      @user = user
    end

    def call
      transaction do
        user.class.update_counters(user.id, failed_attempts: 1)
        user.update(status: 'inactive', status_updated_at: DateTime.now)
      end
    end

RSpec 测试很简单,但是用MiniTest怎么写呢?我很简单:

require 'test_helper'

class FailedAttributesTest < ActiveSupport::TestCase
  setup do
    @user = users(:registered)
  end
end

以及如何将 @user 变量传递给 运行 class 并检查 @user 是否已更新?

Minitest 实际上只是一个非常简单的 TDD 设置,对如何编写测试几乎没有意见。

Minitest::Test 没有内置等同于 let/let! 或 RSpec 中的隐式主语。相反,依赖项通常在 setup 块中设置:

require 'test_helper'

class FailedAttributesTest < ActiveSupport::TestCase
  # Arrange
  setup do
    @user = users(:registered)
    @service = FailedAttributes.new(@user)
  end

  def test_does_something
    # Act
    @service.call
    # Assert
    assert_equals(@user.reload.foo, 'bar')
  end
end

如果你想创建类似于 RSpec 中的 let 的记忆辅助方法:

require 'test_helper'

class FailedAttributesTest < ActiveSupport::TestCase

  def test_does_something
    # Act
    service.call
    # Assert
    assert_equal(user.reload.foo, 'bar')
  end

  private

  def user
    @user ||= users(:registered)
  end

  def service
    @service ||= FailedAttributes.new(user) 
  end
end

至于如何测试服务对象——这真的是一个几乎不可能涵盖的主题,因为服务对象实际上只是一种设计模式,它包括编写执行单个工作的简单对象,并将所有需要的输入作为构造函数或方法参数。测试它们实际上与测试任何其他类型的对象没有什么不同。