Rails로 범위 테스트하기

12845 단어 railsruby

문제



내가 보았고 이해하는 데 오랜 시간이 걸린 일반적인 문제는 Rails 스코프를 적절하게 테스트하는 방법이었습니다. 범위를 적절하게 테스트하는 방법과 실제로 문제를 해결하지 못하는 오래된 stackoverflow 게시물을 찾는 방법에 대해 온라인에서 여러 번 검색했습니다.

테스트하기 어려운 이유는 무엇입니까?



범위는 일반적으로 많은 수의 고정 장치를 포함하는 경우 전역 데이터가 테스트에 누출되어 테스트가 간헐적으로 실패할 수 있는 전체 데이터베이스에서 작동하기 때문에 테스트하기 어려울 수 있습니다.

순진한 접근



처음에는 스코프가 작동하는 경향이 있는 ActiveRecord::Relation를 "스텁"할 생각이었지만, 데이터를 스텁 아웃하는 것은 오류가 발생하기 쉽고 엄격하며 제대로 하기 어렵다는 것을 알았습니다.

알려진 데이터 세트에서 작동하는 접근 방식



이것과 오랫동안 씨름한 끝에 나는 마침내 깨달았다. 스코프를 알려진 데이터 세트에 연결하고 테스트 케이스에 사용하십시오! 하지만 어떻게 해야 할까요? 가장 쉬운 방법은 레코드 세트를 만든 다음 레코드 세트id를 모델의 where() 쿼리로 전달하는 것입니다. 예를 들어 보겠습니다.
User라는 모델이 있고 최신 사용자와 가장 오래된 사용자 모두에 대한 범위를 갖고 싶다고 가정해 보겠습니다.

당신이 나와 같다면 날짜/시간 열에 대한 ASC와 DESC의 차이점을 결코 알지 못할 것입니다.

따라서 스코프를 빠르게 추가한 다음 올바르게 설정되었는지 확인합니다.

class User < ActiveRecord::Base
  scope :newest, -> { order(created_at: :asc) }
  scope :oldest, -> { order(created_at: :desc) }
end


이제 어떻게 테스트할 수 있을까요?

음, 모델 테스트에서 먼저 몇 명의 사용자를 설정해야 합니다.

class UserTest < ActiveSupport::TestCase
  def setup
    @user_one = User.create!(created_at: 1.day.ago)
    @user_two = User.create!(created_at: 2.days.ago)
    @user_three = User.create!(created_at: 3.days.ago)

    # This lets us have a known set of data. We don't have a polluted global scope of users.
    @users = User.where(id: [@user_one.id, @user_two.id, @user_three.id])
  end
end


이제 알려진 데이터 집합이 있으므로 이를 연결 해제하고 범위를 테스트합니다.

class UserTest < ActiveSupport::TestCase
  def setup
    # ...
  end

  test "Newest users and oldest users should be sorted properly" do
    # By testing both newest and oldest, we're coupling these tests together
    # We test both just in case our records just happen to be returned in the correct order.
    # we could use reverse_scope to test newest, but instead we just make this explicit.

    # chain off of @users so we use a known set of data rather than the whole database.
    newest_users = @users.newest
    assert_operator newest_users.first.created_at, :>=, newest_users.second.created_at
    assert_operator newest_users.first.created_at, :>=, newest_users.third.created_at
    assert_operator newest_users.second.created_at, :>=, newest_users.third.created_at

    oldest_users = @users.oldest
    assert_operator oldest_users.first.created_at, :<=, oldest_users.second.created_at
    assert_operator oldest_users.first.created_at, :<=, oldest_users.third.created_at
    assert_operator oldest_users.second.created_at, :<=, oldest_users.third.created_at
  end
end


이 테스트를 실행하면 다음과 같은 결과가 나타납니다.

ruby user_test.rb

# Running:

F

Finished in 0.013149s, 76.0489 runs/s, 76.0489 assertions/s.

  1) Failure:
UserTest#test_Newest_users_and_oldest_users_should_be_sorted_properly [single_line_active_record.rb:52]:
Expected 2022-04-05 18:15:24.185615 UTC to be >= 2022-04-06 18:15:24.184933 UTC.


이런! 실패했습니다... 열 방향이 잘못되었을 수 있습니다. 이것을 시도해 봅시다:

class User < ActiveRecord::Base
-  scope :newest, -> { order(created_at: :asc) }
+  scope :newest, -> { order(created_at: :desc) }


-  scope :oldest, -> { order(created_at: :desc) }
+  scope :oldest, -> { order(created_at: :asc) }
end


그런 다음 다시 테스트하십시오.

ruby user_test.rb

# Running:

.

Finished in 0.021307s, 46.9331 runs/s, 281.5983 assertions/s.

1 runs, 6 assertions, 0 failures, 0 errors, 0 skips


이야 우리가 해냈어!!

다른 범위 추가



자, 첫 번째 범위 테스트는 이 제한된 범위에서 그다지 유용하지 않았을 수 있으므로 특정 날짜/시간 이후에 생성된 사용자를 확인하는 제외 범위를 만들어 보겠습니다.

망원경




class User < ApplicationRecord
  scope :created_after, ->(date) { where("created_at >= ?", date) }
end


시험




class UserTest < ActiveSupport::TestCase
  test "Should only show users created from 2 days ago and later" do
    # Always use beginning of day. I believe 2.days.ago drops the "time" causing it to act like
    # #end_of_day which will cause our user created "2.days.ago" to be excluded.
    users = @users.created_after(2.days.ago.beginning_of_day)

    # We know there should only be 2 users created within the last 2 days.
    assert_equal users.size, 2

    assert_includes users, @user_one
    assert_includes users, @user_two
  end
end


접지




$ ruby user_test.rb

# Running:

..

Finished in 0.024298s, 82.3114 runs/s, 452.7127 assertions/s.

2 runs, 11 assertions, 0 failures, 0 errors, 0 skips


마무리



이제 이것이 이러한 유형의 제한된 범위 테스트에 유용한 확인created_at의 첫 번째 사용 사례입니까? 아마. 생성 시간을 테스트하는 이 특정 테스트의 경우 정렬 알고리즘이 올바르게 수행할 것으로 기대하므로 문제가 되지 않습니다. 그러나 데이터 범위가 제한된 이 방법을 사용하면 다른 테스트/픽스처의 데이터가 누출될 수 있는 고급 범위 및 범위를 테스트하기가 더 쉬워지고 결과를 훨씬 더 쉽게 테스트할 수 있습니다. 또한 created_after 범위에서 수행한 것처럼 제외 범위/쿼리에서도 훌륭하게 작동합니다.

휴양



이 테스트를 단일 파일로 다시 만드는 요지는 여기에서 찾을 수 있습니다.

https://gist.github.com/ParamagicDev/f59d02bed10308c9ca60a43c87de26d9

좋은 웹페이지 즐겨찾기