1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rspecのchangeマッチャーを使う時、初期状態の設定をsubjectでやるのってありですか?

Last updated at Posted at 2021-08-06

はじめに

普段はC++とかTypeScriptのように型がある言語が好きな私。

最近業務でRubyとRailsとMySQLとRspecとかいう全部わからないし、しかもRubyって型がない。そんなものを使うことになって苦戦しつつも勉強して仕事しています、たのしい。

問題提起

突然ですが下のRspecのコードを見てみて下さい(疑似コード)

# frozen_string_literal: true

require 'spec_helper'

describe "test" do
  def put_value(v)
    # なにかside effectを起こす
  end

  subject do
    put_value "before"
    lambda do
      put_value "after"
    end
  end

  it { is_expected.to change { some_value }.from("before").to("after") }
end

意図としては、subjectの中で初期状態の設定を行って、変化を生じさせる操作もsubjectの中のlambdaに書くことで、beforeとかletを排除して直線的に何が変化するのか読めるようにするというものです。

なあにこのlambdaという人は以下の記事を。

こういう書き方はありかどうか、これがこの記事の問題提起です。

評価順序の予想

  1. subject に渡したblock
  2. is_expected : https://github.com/rspec/rspec-core/blob/dc898adc3f98d841a43e22cdf62ae2250266c7b6/lib/rspec/core/memoized_helpers.rb#L120-L122
  3. expect
  4. change
  5. (change return object)#from
  6. (change return object)#to
  7. RSpec::Expectations::ExpectationTarget::InstanceMethods#to

反論

そもそもbefore使えばいいのでは

# frozen_string_literal: true

require 'spec_helper'

describe "test" do
  def put_value(v)
    # なにかside effectを起こす
  end

  subject { -> { put_value_after } }

  before do
    put_value "before"
  end

  let(:put_value_after) do
    put_value "after"
  end

  it { is_expected.to change { some_value }.from("before").to("after") }
end

before は「最初にこれがあります」という前提条件の提示なのでbeforeは排除したくないというもの(職場の先輩の主張)。

自分はsubjectは先頭に書かれるべきだと思っているし、RubocopでRspec/LeadingSubjectを有効にしています。

すると見た目はsubjectbeforeletなのに実際の順序はbeforesubjectletとなってしまい、上から下にコードを読めなくなってしまいます。

そもそもsubjectは必要か?

# frozen_string_literal: true

require 'spec_helper'

describe "test" do
  def put_value(v)
    # なにかside effectを起こす
  end

  before do
    put_value "before"
  end

  let(:put_value_after) do
    put_value "after"
  end

  it { expect { put_value_after }.to change { some_value }.from("before").to("after") }
end

is_expectedにしようとsubjectつかうから話がややこしいのであって、それをやめればすっきりするのでは?というもの。

結局冒頭のコードは断念してこちらを今回は採用することにしたのでした。

終わりに

自分はRuby学び始めて1カ月の初心者なのでRubyのプロたちの意見をお待ちしています。

余談

マッチャーと書くと抹茶に変換されがちな現象ありませんか?もう🍵でよくないですか?(だめです

1
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?