- 마이그레이션 테스트를 작성해야 하는 시기
- 이 방법은 어떻게 작동합니까?
-
ActiveRecord::Migration
클래스 테스트 -
ActiveRecord::Migration
클래스가 아닌 것을 테스트하는 방법
GitLab에서의 Rails 마이그레이션 테스트
신뢰할 수 있는 Rails 마이그레이션을 확인하기 위해서는 데이터베이스 스키마에 대해 테스트해야 합니다.
마이그레이션 테스트를 작성해야 하는 시기
- Post 마이그레이션(
/db/post_migrate
) 및 백그라운드 마이그레이션(lib/gitlab/background_migration
)은 반드시 마이그레이션 테스트를 수행해야 합니다. - 마이그레이션이 데이터 마이그레이션인 경우에는 반드시 마이그레이션 테스트를 수행해야 합니다.
- 필요한 경우 다른 마이그레이션에 대해서도 마이그레이션 테스트를 수행할 수 있습니다.
우리는 스키마 변경만 수행하는 post 마이그레이션에 대해서는 테스트를 강제로 요구하지 않습니다.
이 방법은 어떻게 작동합니까?
(ee/)spec/migrations/
및 spec/lib/(ee/)background_migrations
의 모든 specs는 자동으로 :migration
RSpec 태그와 함께 태깅됩니다. 이 태그는 우리의 spec/support/migration.rb
에서 사용자 정의 RSpec before
및 after
후크를 활성화시킵니다. :gitlab_main
과 같은 데이터베이스 스키마에 대한 마이그레이션을 수행하는 경우 migration: :gitlab_ci
와 같이 RSpec 태그를 명시적으로 지정해야 합니다. 예를 들어 참조하려면 spec/migrations/change_public_projects_cost_factor_spec.rb를 참조하세요.
before
후크는 테스트 중인 마이그레이션이 이전 마이그레이션 버전으로 마이그레이트되지 않은 지점으로 모든 마이그레이션을 롤백시킵니다.
즉, 우리의 사용자 정의 RSpec 후크는 이전 마이그레이션을 찾고 데이터베이스를 이전 마이그레이션 버전으로 다운 마이그레이트합니다.
이 접근법을 통해 데이터베이스 스키마에 대해 마이그레이션을 테스트할 수 있습니다.
after
후크는 데이터베이스를 업 마이그레이트하고 최신 스키마 버전을 복원하여 이 프로세스가 후속 specs에 영향을 미치지 않도록하고 올바른 격리를 보장합니다.
ActiveRecord::Migration
클래스 테스트
ActiveRecord::Migration
클래스(예: db/migrate
또는 db/post_migrate
의 일반 마이그레이션)를 테스트하려면 Rails에 의해 자동으로 로드되지 않기 때문에 require_migration!
도우미 메서드를 사용하여 마이그레이션 파일을 로드해야 합니다.
예시:
require 'spec_helper'
require_migration!
RSpec.describe ...
테스트 도우미
require_migration!
마이그레이션 파일은 Rails에 의해 자동으로로드되지 않으므로 마이그레이션 파일을 매뉴얼으로 로드해야 합니다. 이를 위해 require_migration!
도우미 메서드를 사용할 수 있으며, 이를 통해 스펙 파일 이름을 기반으로 올바른 마이그레이션 파일을 자동으로로드할 수 있습니다.
예를 들어 파일 이름에 스키마 버전이 포함된 스펙 파일에서 마이그레이션 파일을 로드하기 위해 require_migration!
을 사용할 수 있습니다.
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe PopulateFooColumn do
...
end
일부 경우에는 여러 마이그레이션 파일을 요구하여 스펙에서 사용해야 할 수 있습니다. 여기서 스펙 파일과 다른 마이그레이션 파일 사이에는 패턴이 없습니다. 따라서 마이그레이션 파일 이름을 다음과 같이 제공할 수 있습니다.
# frozen_string_literal: true
require 'spec_helper'
require_migration!
require_migration!('populate_bar_column')
RSpec.describe PopulateFooColumn do
...
end
table
임시 ActiveRecord::Base
파생 모델을 생성하기 위해 table
도우미를 사용합니다. FactoryBot은 마이그레이션 스펙에 대한 데이터를 생성하는 데 사용하면 안 됩니다. 왜냐하면 애플리케이션 코드에 의존하고 있으며 마이그레이션이 실행된 후 변경될 수 있기 때문에 테스트가 실패할 수 있습니다. 예를 들어 projects
테이블에 레코드를 생성하려면:
project = table(:projects).create!(id: 1, name: 'gitlab1', path: 'gitlab1')
migrate!
테스트 중인 마이그레이션을 실행하려면 migrate!
도우미를 사용합니다. 이는 마이그레이션을 실행하고 schema_migrations
테이블에서 스키마 버전을 업데이트하는 역할을 합니다. after
후크에서 나머지 마이그레이션을 트리거하기 때문에 어디서부터 시작해야 하는지 파악해야 하기 때문에 필요합니다. 예시:
it '성공적으로 마이그레이션됩니다' do
# ... 마이그레이션 전 기대 동작
migrate!
# ... 마이그레이션 후 기대 동작
end
reversible_migration
change
또는 up
및 down
후크 중 하나 또는 둘 다를 사용하여 마이그레이션을 테스트하기 위해 reversible_migration
도우미를 사용합니다. 이는 마이그레이션이 실행된 후 애플리케이션 및 해당 데이터의 상태가 처음에 마이그레이션이 실행되기 전과 동일한지를 테스트합니다. 이 도우미는 다음을 수행합니다:
- Up 마이그레이션 이전의 기대 동작을 수행합니다.
- Up 마이그레이션을 실행합니다.
- After 기대 동작을 수행합니다.
- Down 마이그레이션을 실행합니다.
-
before
기대 동작을 두 번째로 수행합니다.
예시:
reversible_migration do |migration|
migration.before -> {
# ... 마이그레이션 이전 기대 동작
}
migration.after -> {
# ... 마이그레이션 후 기대 동작
}
end
배포 후 마이그레이션에 대한 사용자 정의 매처
우리는 일부 사용자 정의 매처를 spec/support/matchers/background_migrations_matchers.rb
에 가지고 있어 배포 후 백그라운드 마이그레이션에 대해 올바르게 예약되었음을 확인합니다. 또한 올바른 수의 인수를 수신했는지 확인합니다.
모든 매처는 be_background_migration_with_arguments
라는 내부 매처를 사용하며, 이는 마이그레이션 클래스의 #perform
메서드가 제공된 인수를 수신할 때 크래시하지 않는지를 확인합니다.
be_scheduled_migration
예상된 클래스 및 인수로 Sidekiq 작업이 대기열에 들어갔는지 확인합니다.
이 매처는 보통 우리의 도우미를 통과하지 않고 매뉴얼으로 작업을 대기열에 넣는 경우에 사용됩니다.
# 마이그레이션
BackgroundMigrationWorker.perform_async('MigrationClass', args)
# 스펙
expect('MigrationClass').to be_scheduled_migration(*args)
be_scheduled_migration_with_multiple_args
예상된 클래스 및 인수로 Sidekiq 작업이 대기열에 들어갔는지 확인합니다.
이는 be_scheduled_migration
과 같이 작동하지만 배열 인수를 비교할 때 순서가 무시됩니다.
# 마이그레이션
BackgroundMigrationWorker.perform_async('MigrationClass', ['foo', [3, 2, 1]])
# 스펙
expect('MigrationClass').to be_scheduled_migration_with_multiple_args('foo', [1, 2, 3])
be_scheduled_delayed_migration
예상된 지연, 클래스 및 인수로 Sidekiq 작업이 대기열에 들어갔는지 확인합니다.
이는 delay
와 관련된 도우미들과 함께 사용할 수 있습니다.
# 마이그레이션
BackgroundMigrationWorker.perform_in(delay, 'MigrationClass', args)
# 스펙
expect('MigrationClass').to be_scheduled_delayed_migration(delay, *args)
have_scheduled_batched_migration
예상된 클래스 및 인수로 BatchedMigration
레코드가 생성되었는지 확인합니다.
*args
는 MigrationClass
에 전달된 추가 인수이고, **kwargs
는 BatchedMigration
레코드에서 확인할 다른 속성입니다(예: interval: 2.minutes
).
# 마이그레이션
queue_batched_background_migration(
'MigrationClass',
table_name,
column_name,
*args,
**kwargs
)
# 스펙
expect('MigrationClass').to have_scheduled_batched_migration(
table_name: table_name,
column_name: column_name,
job_arguments: args,
**kwargs
)
be_finalize_background_migration_of
마이그레이션이 finalize_background_migration
을 호출하는지 확인합니다.
# 마이그레이션
finalize_background_migration('MigrationClass')
# 스펙
expect(described_class).to be_finalize_background_migration_of('MigrationClass')
마이그레이션 테스트 예시
마이그레이션 테스트는 마이그레이션이 정확히 무엇을 하는 지에 따라 다양한데, 가장 흔한 유형은 데이터 마이그레이션과 백그라운드 마이그레이션을 스케줄링 하는 것입니다.
데이터 마이그레이션 테스트 예시
이 명세는 db/post_migrate/20200723040950_migrate_incident_issues_to_incident_type.rb
마이그레이션을 테스트합니다. 전체 명세는 spec/migrations/migrate_incident_issues_to_incident_type_spec.rb
에서 찾을 수 있습니다.
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe MigrateIncidentIssuesToIncidentType do
...
end
백그라운드 마이그레이션 스케줄링 테스트 예시
보통 이를 테스트하려면 다음을 수행해야 합니다:
- 레코드를 생성합니다.
- 마이그레이션을 실행합니다.
- 기대한 작업이 올바르게 스케줄링되었는지, 올바른 레코드 세트와 배치 크기, 간격 등이 올바른지 확인합니다.
백그라운드 마이그레이션의 동작 자체는 백그라운드 마이그레이션 클래스에 대한 별도의 테스트에서 확인해야 합니다.
이 명세는 db/post_migrate/20210701111909_backfill_issues_upvotes_count.rb
포스트-배포 마이그레이션을 테스트합니다. 전체 명세는 spec/migrations/backfill_issues_upvotes_count_spec.rb
에서 찾을 수 있습니다.
require 'spec_helper'
require_migration!
RSpec.describe BackfillIssuesUpvotesCount do
...
end
ActiveRecord::Migration
클래스가 아닌 것을 테스트하는 방법
ActiveRecord::Migration
클래스가 아닌 것(백그라운드 마이그레이션)을 테스트하려면 필요한 스키마 버전을 매뉴얼으로 제공해야 합니다. 스키마를 변경하려는 컨텍스트에 schema
태그를 추가합니다.
설정되지 않으면 schema
는 기본적으로 :latest
로 설정됩니다.
예시:
describe SomeClass, schema: 20170608152748 do
# ...
end
백그라운드 마이그레이션 테스트 예시
이 명세는 lib/gitlab/background_migration/backfill_draft_status_on_merge_requests.rb
백그라운드 마이그레이션을 테스트합니다. 전체 명세는 spec/lib/gitlab/background_migration/backfill_draft_status_on_merge_requests_spec.rb
에서 찾을 수 있습니다.
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillDraftStatusOnMergeRequests do
...
end
이러한 테스트는 데이터베이스 트랜잭션 내에서 실행되지 않으므로, 삭제 데이터베이스 정리 전략을 사용합니다. 트랜잭션이 있는 것에 의존하지 마십시오.