実験のテスト

RSpecによる実験のテスト

実験を行う過程で、RSpec ツールを使用したいと思うかもしれません。これはspec/experiments にあるファイルでは自動的に行われますが、その他のファイルや仕様に含める場合は、:experiment タイプを指定します:

it "tests experiments nicely", :experiment do
end

スタブヘルパー

stub_experiments を使って実験をスタブすることができます。実験名をキー、解決したい variant を値としてハッシュを渡します:

# Ensures the experiments named `:example` & `:example2` are both "enabled" and
# that each will resolve to the given variant (`:my_variant` and `:control`
# respectively).
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 chain メソッドを使うと、次のインスタンスで実験が行われるように指定できます。これはexperiment(:example).track をダウンストリームで呼び出す場合に役立ちます:

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

experiment(:example).track(:my_event)

track matcher にチェーンできるメソッドの完全な例:

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 specs のこのスタブ方法は、テストの終了時に自動的にスタブを解除するわけではありません。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' });
    // ...
  });
})