실험 테스트

RSpec을 사용한 실험 테스트

실험을 진행하는 과정에서 RSpec 도구를 사용할 수 있습니다. 이는 spec/experiments의 파일에 대해서는 자동으로 발생하지만, 다른 파일 및 스펙에 대해서는 :experiment 유형을 명시할 수 있습니다.

it "tests experiments nicely", :experiment do
end

Stub 헬퍼

stub_experiments를 사용하여 실험을 stubbing할 수 있습니다. 실험의 이름을 키로 사용하고, 각각을 해결해야 하는 변형으로 사용하는 값으로 하는 해시를 전달하세요.

# `:example` 및 `:example2`라는 실험이 모두 "enabled"되어 있고 각각 지정된 변형(`:my_variant` 및 `:control`)으로 해결됨을 보장합니다.
stub_experiments(example: :my_variant, example2: :control)

experiment(:example) do |e|
  e.enabled? # => true
  e.assigned.name # => 'my_variant'
end

experiment(:example2) do |e|
  e.enabled? # => true
  e.assigned.name # => 'control'
end

제외, 분할 및 동작 매처

등록된 동작, 제외 및 분할을 테스트할 수 있습니다.

class ExampleExperiment < ApplicationExperiment
  control { }
  candidate { '_candidate_' }
  
  exclude { context.actor.first_name == 'Richard' }
  segment(variant: :candidate) { context.actor.username == 'jejacks0n' }
end

excluded = double(username: 'rdiggitty', first_name: 'Richard')
segmented = double(username: 'jejacks0n', first_name: 'Jeremy')

# register_behavior 매처
expect(experiment(:example)).to register_behavior(:control)
expect(experiment(:example)).to register_behavior(:candidate).with('_candidate_')

# exclude 매처
expect(experiment(:example)).to exclude(actor: excluded)
expect(experiment(:example)).not_to exclude(actor: segmented)

# segment 매처
expect(experiment(:example)).to segment(actor: segmented).into(:candidate)
expect(experiment(:example)).not_to segment(actor: excluded)

추적 매처

추적 이벤트는 실험의 주요 측면입니다. 추적 호출이 적절하게 커버되도록 유연한 방식으로 제공하려고 합니다.

이를 인스턴스 레벨에서 또는 “모든 인스턴스” 레벨에서 수행할 수 있습니다.

subject = experiment(:example)

expect(subject).to track(:my_event)

subject.track(:my_event)

다음 인스턴스에서 발생하도록 지정하려면 on_next_instance 체인 메서드를 사용할 수 있습니다. 이는 downstream에서 experiment(:example).track를 호출하는 경우 도움이 됩니다.

expect(experiment(:example)).to track(:my_event).on_next_instance

experiment(:example).track(:my_event)

track 매처에 체인할 수 있는 메서드의 전체 예시:

expect(experiment(:example)).to track(:my_event, value: 1, property: '_property_')
  .on_next_instance
  .with_context(foo: :bar)
  .for(:variant_name)

experiment(:example, :variant_name, foo: :bar).track(:my_event, value: 1, property: '_property_')

Jest로 테스트

스텁 헬퍼

spec/frontend/__helpers__/experimentation_helper.js에 정의된 stubExperiments 헬퍼를 사용하여 실험을 스텁할 수 있습니다.

import { stubExperiments } from 'helpers/experimentation_helper';
import { getExperimentData } from '~/experimentation/utils';

describe('when my_experiment is enabled', () => {
  beforeEach(() => {
    stubExperiments({ my_experiment: 'candidate' });
  });
  
  it('sets the correct data', () => {
    expect(getExperimentData('my_experiment')).toEqual({ experiment: 'my_experiment', variant: 'candidate' });
  });
});
note
이 방법을 사용하여 Jest 스펙에서 스텁을 하는 경우 테스트가 종료된 후 자동으로 스텁이 제거되지 않습니다. 우리는 스텁된 실험을 window.gl의 모든 다른 전역 데이터와 Merge합니다. 테스트 이후에 스텁된 실험을 제거하거나 테스트 전에 깨끗한 글로벌 개체를 보장해야하는 경우, 전역 개체를 직접 관리해야 합니다.
describe('tests that care about global state', () => {
  const originalObjects = [];
  
  beforeEach(() => {
    // 현재는 window.gon & window.gl을 모두 사용하기 때문에 하위 호환성을 위해 사용한다. 
    originalObjects.push(window.gon, window.gl);
  });
  
  afterEach(() => {
    [window.gon, window.gl] = originalObjects;
  });
  
  it('stubs experiment in fresh global state', () => {
    stubExperiment({ my_experiment: 'candidate' });
    // ...
  });
})