InfoGrab DocsInfoGrab Docs

실험 테스트

요약

실험을 다루다 보면 내장된 RSpec 도구를 사용하고 싶을 수 있습니다. :experiment 타입 없이도 사용할 수 있는 stub_experiments로 실험을 스텁 처리할 수 있습니다. 매처를 사용하면 등록된 동작, 제외, 세그멘테이션 같은 항목도 테스트할 수 있습니다.

RSpec으로 실험 테스트#

실험을 다루다 보면 내장된 RSpec 도구를 사용하고 싶을 수 있습니다. spec/experiments의 파일에서는 자동으로 적용되지만, 그 밖의 파일과 스펙에 포함하려면 :experiment 타입을 지정합니다.

it "tests experiments nicely", :experiment do
end

Stub 헬퍼#

:experiment 타입 없이도 사용할 수 있는 stub_experiments로 실험을 스텁 처리할 수 있습니다. 실험 이름을 키로, 각 실험이 해석될 배리언트를 값으로 하는 해시를 전달합니다.

# Ensures the experiments named `:example` & `:example2` are both "enabled" and
# that each will resolve to the given variant (`:my_variant` and `: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 matcher
expect(experiment(:example)).to register_behavior(:control)
expect(experiment(:example)).to register_behavior(:candidate).with('_candidate_')

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

# segment matcher
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 체인 메서드를 사용하면 해당 실험의 다음 인스턴스에서 트래킹이 일어난다고 지정할 수 있습니다. 하위 흐름에서 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_')

실험이 발생시키는 이벤트 검증#

track 매처는 실험에 무언가를 트래킹하도록 요청했는지를 검증합니다. Snowplow에 도달하는 페이로드는 확인하지 않으며, 브라우저가 보내는 이벤트는 전혀 확인하지 못합니다.

두 가지를 모두 검증하려면 기능 스펙에 :capture_snowplow_events 태그를 붙이고 각 배리언트가 발생시켜야 하는 이벤트를 트래킹 여정 계약에 선언합니다. 계약은 실험 이름을 한 번만 지정하므로, 테스트 대상 분기의 모든 이벤트도 해당 실험의 컨텍스트를 함께 담아야 합니다.

expect_snowplow_tracking_journey('whats_new_placement', variant: variant)

계약 형식과 나머지 동작 방식은 기능 스펙에서 Snowplow 이벤트 캡처를 참고합니다.

Jest로 테스트#

Stub 헬퍼#

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의 다른 전역 데이터와 함께 병합됩니다. 테스트 후 스텁 처리한 실험을 제거하거나 테스트 전에 깨끗한 전역 객체를 보장해야 한다면, 전역 객체를 직접 관리해야 합니다.

describe('tests that care about global state', () => {
  const originalObjects = [];

  beforeEach(() => {
    // For backwards compatibility for now, we're using both 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' });
    // ...
  });
})

실험 테스트

GitLab v19.4
원문 보기

요약

실험을 다루다 보면 내장된 RSpec 도구를 사용하고 싶을 수 있습니다. :experiment 타입 없이도 사용할 수 있는 stub_experiments로 실험을 스텁 처리할 수 있습니다. 매처를 사용하면 등록된 동작, 제외, 세그멘테이션 같은 항목도 테스트할 수 있습니다.

RSpec으로 실험 테스트#

실험을 다루다 보면 내장된 RSpec 도구를 사용하고 싶을 수 있습니다. spec/experiments의 파일에서는 자동으로 적용되지만, 그 밖의 파일과 스펙에 포함하려면 :experiment 타입을 지정합니다.

it "tests experiments nicely", :experiment do
end

Stub 헬퍼#

:experiment 타입 없이도 사용할 수 있는 stub_experiments로 실험을 스텁 처리할 수 있습니다. 실험 이름을 키로, 각 실험이 해석될 배리언트를 값으로 하는 해시를 전달합니다.

# Ensures the experiments named `:example` & `:example2` are both "enabled" and
# that each will resolve to the given variant (`:my_variant` and `: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 matcher
expect(experiment(:example)).to register_behavior(:control)
expect(experiment(:example)).to register_behavior(:candidate).with('_candidate_')

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

# segment matcher
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 체인 메서드를 사용하면 해당 실험의 다음 인스턴스에서 트래킹이 일어난다고 지정할 수 있습니다. 하위 흐름에서 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_')

실험이 발생시키는 이벤트 검증#

track 매처는 실험에 무언가를 트래킹하도록 요청했는지를 검증합니다. Snowplow에 도달하는 페이로드는 확인하지 않으며, 브라우저가 보내는 이벤트는 전혀 확인하지 못합니다.

두 가지를 모두 검증하려면 기능 스펙에 :capture_snowplow_events 태그를 붙이고 각 배리언트가 발생시켜야 하는 이벤트를 트래킹 여정 계약에 선언합니다. 계약은 실험 이름을 한 번만 지정하므로, 테스트 대상 분기의 모든 이벤트도 해당 실험의 컨텍스트를 함께 담아야 합니다.

expect_snowplow_tracking_journey('whats_new_placement', variant: variant)

계약 형식과 나머지 동작 방식은 기능 스펙에서 Snowplow 이벤트 캡처를 참고합니다.

Jest로 테스트#

Stub 헬퍼#

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의 다른 전역 데이터와 함께 병합됩니다. 테스트 후 스텁 처리한 실험을 제거하거나 테스트 전에 깨끗한 전역 객체를 보장해야 한다면, 전역 객체를 직접 관리해야 합니다.

describe('tests that care about global state', () => {
  const originalObjects = [];

  beforeEach(() => {
    // For backwards compatibility for now, we're using both 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' });
    // ...
  });
})