自動テスト link

Ren'Py はクリエイターがゲームに自動テストを行い、ゲームへの変更が既存の機能が損なわないか確認できるようにします。これは大規模なゲームや頻繁に更新されるゲームに特に便利です。

テストシステムの主要な 2 つの要素は、 testcase ステートメントと testsuite ステートメントです。

renpy.is_in_test() 関数はテストが現在実行中かどうかを知るのに役立ちます。

テストケースの実行 link

テストケースは2つの方法で実行できます。1つ目は、ランチャーから "Run Testcases" ボタンを選択して行われます。2つ目はコマンドラインから、 テストコマンド を使います。いずれの場合も、 global と名付けられたテストケースまたはテストスイートはデフォルトで実行されます。

”Run Testcases" ボタンは、グローバルテストスイートに少なくとも1つのテストケースがある場合のみランチャーに出現します。 Ren'Py スクリプトファイルの最上位にあるテストケースやテストスイートは、自動的にグローバルテストスイートに追加されます。最初のテストケースをプロジェクトに追加する際は、通常通りゲームを起動し、ランチャーで refresh を押すと Run Testcases ボタンが表示されます。

Testcase ステートメント link

testcase ステートメントは名前付きテストケースを作成します。各ケースにはテストステートメントのブロックを含みます(下記参照)。テストケースはRen'Pyの label に似ていますが、いくつかの違いがあります :

  • Ren'Pyの label ステートメントは Ren'Py のコードを扱い、 testcase ステートメントは(このページにリストされた)テストステートメントを扱います。これらは相互に排他的なものです。

  • return ステートメントに等しいテストケースはありません。

  • テストブロックの外にテストステートメントはおけませんが、ラベルの外(initブロック内など)にRen'Pyコードは置けます。

これは次のプロパティーを受け取ります。 :

description link

テストケースを説明する文字列です。これはテストレポートで使用されます。

enabled link

この式が False と評価された場合、このテストはスキップされます。デフォルトは True です。

これは例えば、サポートされないプラットフォーム上など、条件によってテストを無効化します。

testcase windows:
    enabled renpy.windows
    ...

testcase not_on_mobile:
    enabled not renpy.mobile
    ...

詳細は テストケースのスキップ をご覧ください。

only link

この式が True と評価された場合、このテストケース(および only True を含む他のテスト)のみが実行されます。デフォルトは False です。

詳細は テストケースのスキップ をご覧ください。

xfail link

この式が True と評価された場合、このテストケースは失敗が期待されます。テストが失敗すれば、 failed の代わりに xfailed とマークされます。デフォルトでは False です。

parameter link

変数名(または変数名のタプル)と値のリスト(または値のタプルのリスト)です。このテストはリスト内の各値(または値のタプル)に対して1回ずつ実行されます。

テストには複数の parameter プロパティーを持てる場合があり、その場合テストはすべての可能な値の組み合わせに対して実行されます。

詳細は パラメーター化されたテスト を参照してください。

Testsuiteステートメント link

testsuite ステートメントはテストケースをまとめるために使われます。テストスイートはテストケース、他のテストスイート、フック(下記参照)を含みます。

デフォルトのテストスイートは global という名づけられ、ユーザーが指定しなければ Ren'Py によって自動的に作成されます。これは、ゲーム内の他のすべてのトップレベルのテストスイートとテストケースが含みます。

testcase ステートメント と同じプロパティーを受け取ります。

フック link

testsuite ステートメントは以下のフックを含められます:

setup

現在のスイートに含まれるテストを実行する前に一度だけ実行されるテストステートメントのブロックです。

before testsuite

現在のスイート内の各テストスイート前に繰り返し実行されるテストステートメントのブロックです。

before testcase

現在のスイート内の各テストケース前に繰り返し実行されるテストステートメントのブロックです。

after testcase

現在のスイート内の各テストケース後に繰り返し実行されるテストステートメントのブロックです。テストケースが失敗したり例外が発生しても、このプログラムは実行されます。

after testsuite

現在のスイート内の各テストスイート後に繰り返し実行されるテストステートメントのブロックです。テストスイートが失敗したり例外を発生させても、このプログラムは実行されます。

teardown

現在のスイートに含まれるすべてのテスト実行後に一度だけ実行されるテストステートメントのブロックです。テストが失敗したり例外が発生しても、この動作は実行されます。

before *after * フックは以下のプロパティーを持ちます :

depth link

フックを適用する深さを指定する整数です。

テストケースに対してはデフォルトでは -1 なり、すべてのネストされたテストスイートとテストケースに適用されます。

テストスイート に対してはデフォルトでは 0 となり、現在のスイートに直接含まれているテストスイートにのみ適用されます。

詳細については、テスト実行のライフサイクル をご覧ください。

テスト実行のライフサイクル link

この章では、テストケースとテストスイートの実行順序と、フックの呼び出し方法について説明します。次の例ではこれを示しています。

コード

実行順序

testsuite global:
    # Hooks
    setup:
        skip until main_menu

    before testsuite:
        if not screen "main_menu":
            run MainMenu(confirm=False)
        click "Start"

    before testcase:
        $ print("Starting a testcase.")

    after testcase:
        $ print("Finished a testcase.")

    after testsuite:
        $ print("Finished a testsuite.")

    teardown:
        exit

    # Subtests
    testsuite basic:
        testcase first_testcase:
            advance

    testsuite test_choices:
        # Hooks
        setup:
            run Jump("chapter1")

        before testcase:
            advance until menu choice

        after testcase:
            $ print("Finished a choice test.")

        teardown:
            $ print("Finished all choice tests.")

        # Subtests
        testcase choice1:
            click "First Choice"

        testcase choice2(enabled=False):
            click "Second Choice"

        testcase choice3:
            click "Third Choice"

global :: setup

global :: before testsuite

global :: before testcase

simple :: first_testcase

global :: after testcase

global :: after testsuite

global :: before testsuite

test_choices :: setup

global :: before testcase

test_choices :: before testcase

test_choices :: choice1

test_choices :: after testcase

global :: after testcase

global :: before testcase

test_choices :: before testcase

test_choices :: choice3

test_choices :: after testcase

global :: after testcase

test_choices :: teardown

global :: after testsuite

global :: teardown

なお、 global :: before testcaseglobal :: after testcase は、たとえネストされたテストスイート内であっても、各テストケースの前後に実行されます。

フックの範囲を制限するには、その depth プロパティーを設定します。これを 0 に設定すると、フックはそのフックを含むテストスイート直下のテストのみを実行します。

例 :

testsuite global:
    before testcase:
        depth 0
        $ print("Starting a testcase.")

一方、 before testsuiteafter testsuite フックはデフォルトの depth0 であり、そのフックを含むテストスイート直下のテストスイートのみが実行されます。

ネストされたテストスイートやテストケースを含むようにフックの範囲を拡大するには、その depth プロパティーを -1 (無限深さの場合)または正の整数(特定の深さの場合)に設定します。

注釈

テストスイートの実行が終わっても、ゲームは自動的には閉じません。代わりにゲームのコントロールをプレイヤーに戻し、ユーザーの入力を待ちます。

テストスイートの後にゲームを閉じるには、そのテストスイートの after フックにある exit テストステートメントを使えます。例

testsuite global:
    teardown:
        exit

テストケースのスキップ link

テストケースがスキップされると実行されません。さらに、テストスイートの before testcaseafter testcase フックは、そのテストケースでは実行されません。

もしテストスイートで すべての テストがスキップされた場合、その setupteardown フックも実行されません。さらに before testsuite および after testsuite フックも親テストスイートからは実行されません。

パラメーター化されたテスト link

parameter プロパティーを用いて、異なる値で複数回テストケースを実行できます。

このためには、変数名と値のリストを与えます。テストはリスト内の各値に対して1回ずつ実行されます。例

testcase example:
    parameter x = [1, 2, 3]
    assert eval (x > 0)

これは三回テストを実行し、一回目は x = 1, 二回目は x = 2, 三回目は x = 3 です。

各実行では before testcaseafter testcase フックを実行し、各テストは別々にテストレポートで報告されます。

グループ化されたパラメーター link

複数の変数を括弧内にまとめ、値のグループのリストを指定して、一度に複数の変数群を指定できます。例

testcase addition:
    parameter (x, y, z) = [ (1, 2, 3), (2, 3, 5), (3, 5, 8) ]

    assert eval (x + y == z)

この方法では3回実行され、一度に1セットの値を使用します: (1, 2, 3), (2, 3, 5), (3, 5, 8) です。

パラメーターの組み合わせ link

複数の parameter プロパティーが提供されている場合、テストケースはすべての可能な値の組み合わせに対して実行されます。例

testcase combinations:
    parameter a = [1, 2]
    parameter b = [3, 4]
    parameter c = [5, 6]

    assert eval (a + b + c in [9, 10, 11, 12])

これは8回実行され、各組み合わせの (a, b, c に対して1回ずつ行われます :

(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)

グループ化されたパラメーターと非グループ化パラメーターの混同も可能です。例

testcase mixed:
    parameter a = [1, 2]
    parameter (b, c) = [ (3, 5), (4, 6) ]

    assert eval (a + b + c in [9, 10, 11, 12])

これは (a, (b, c)) の組み合わせを用いて4回実行されます:

(1, (3, 5)), (1, (4, 6)), (2, (3, 5)), (2, (4, 6))

式でのパラメーターの使用 link

式を取るテストプロパティーではパラメーターを使えます。

例えば、これは x の各値に対して3回実行されるテストです。テストは x が 0 または 1のときに合格し、 x が2のときには失敗( xfail )します

testcase choice_test:
    parameter x = [0, 1, 2]
    xfail x == 2

    assert eval (x < 2)

パラメーターを使って名前でスクリーンやボタンの選択もできます。例えば、このテストでは choice_text の値に応じて「1つめ」または「2つめ」のどちらかを選択します。

testcase show_menu:
    parameter screen_name = ["preferences", "load"]

    $ print(f"Showing screen '{screen_name}'")
    run ShowMenu(screen_name)
    pause until screen screen_name
    run Return()

パラメーターは Python コードブロック内でも使用できます。例えば、このテストは現在の xy の値とを表示し、その位置でクリックします:

testcase param_test:
    parameter (x, y) = [(0.0, 0.0), (0.5, 0.5), (1.0, 1.0)]

    $ print(f"Clicking at position ({x}, {y})")
    click pos (x, y)

テストスイート link

パラメーターはテストスイート全体にも提供可能です。この場合、スイート内のすべてのフックとテストケースが各パラメーターセットに対して1回ずつ実行されます。

各パラメーターを利用した実行は setup, before/after testsuite, teardown フックを実行します。

例 :

testsuite math_tests:
    parameter (x, y, z) [ (1, 2, 3), (2, 3, 5), (3, 5, 8) ]

    setup:
        $ print(f"Running math tests with x={x}, y={y}, z={z}")

    testcase addition:
        assert eval (x + y == z)

    testcase multiplication:
        assert eval (x*y == z*y - y*y)

パラメーターはネストされ、すべての組み合わせがテストされます。例

testsuite parameter_field:
    parameter choice_text = ["first", "second"]

    testcase param_test2:
        parameter (x, y) = [(0.0, 0.0), (0.5,0.5)]

        advance until screen "choice"
        click choice_text
        click pos (x, y)

これは (choice_text, (x, y)) の各組み合わせに対して1回ずつ、4回実行されます :

("first", (0.0, 0.0)), ("first", (0.5, 0.5)), ("second", (0.0, 0.0)), ("second", (0.5, 0.5))

警告

テストパラメーターはコピーせず直接テストに渡されます。テスト内で可変なパラメーター(例:リストや辞書)を変更すると、その変更は同じオブジェクトを使う他のテストにも影響を及ぼします。

例外と失敗 link

テストケース中にエラーが発生した場合 :

  1. テストケースの実行は直ぐに実行を停止します

  2. そのテストケースを含むテストスイートの after testcase フックが実行されます

  3. もしテストケースがまだある場合、それらは引き続き実行されます( before testcase フックを含む)

  4. もうテストケースがない場合、そのテストスイートの after フックが実行します

フック中にエラーが発生した場合(例: before testcase) :

  1. そのテストスイートは即座に実行を停止します

  2. そのスイートが他のスイートに呼ばれていたら、親スイートは実行を継続します。

  3. 親スイートがなければ、ゲームはテスト実行を停止します。

テストレポート link

テスト実行後、すべてのテストケースとその結果を一覧にしたレポートがコンソールに出力されます。 --print_details オプションがある場合、レポートには各テストに関する追加情報が含まれます。

以下は The Question を成功裏にテストした後のテストレポートの例です :

テレスレポート例

テスト結果 link

テスト次の結果のいずれかになります :

  • Passed: テストはエラーなく成功裏に終わりました。

  • Failed: テストは実行されましたが、ステートメントの一つが失敗しました。

  • XFailed: テストは失敗すると期待され( xfail プロパティーが True と評価されたため)、実際に失敗しました。

  • XPassed: テストは失敗すると期待された( xfail プロパティーが True と評価されたため)が、パスしました。

  • Skipped: テストがスキップされました。これは enabled プロパティーが False と評価されたか、 Only True の別のテストが存在するためです。

一般的に、テストは passed または xfailed の場合は成功とみなされ、 failed または xpassed の場合は不成功とみなされます。

テスト設定 link

以下の変数を設定してテストの挙動を変えられます :

_test.maximum_framerate link

テスト中に最大フレームレートモードを使用するかを指定する真偽値。これにより、可能であれば画面のリフレッシュ レートを超えるフレームレートのロックが解除されます。デフォルトは True です。

_test.timeout link

テストステートメントが条件を満たすまで待つべき最大秒数を指定する浮動小数です。デフォルトは 10.0 です。

これは( assertuntill のような) timeout プロパティーをサポートするステートメントにステートメント毎に指定すれば上書きできます。

_test.force link

renpy.config.suppress_underlayTrue であってもテストを強制するかどうかを指定する真偽値です。デフォルトは False です。

_test.transition_timeout link

トランジションが完了するまでの最大待機秒数を指定する浮動小数であり、越えるとそれをスキップしてテストを進めます。デフォルトは 5.0 です。

_test.focus_trials link

位置指定なしでセレクターを使用するときに、何回テストシステムに マウスを移動する 有効な場所を探そうとさせるかを指定する整数です。デフォルトは 100 です。

_test.screenshot_directory link

スクリーンショットを保存するディレクトリーを指定する文字列です。デフォルトは tests/screenshots です。

_test.vc_revision link

利用可能ならば、現在のソースツリーのバージョン管理(多くはgit)リビジョンです。デフォルトは :env:`RENPY_TEST_VC_REVISION` doc:環境変数 <environment_variables> または、設定していなければ空文字列になります。

テストステートメント link

テストステートメントはテストケースの構成要素です。これらは大きく分けて、コマンドステートメント、コンディション/セレクターステートメント、コントロールステートメントの3つのカテゴリーに分けられます。

基本的コマンド link

Advance link

Type: Command

advance

ゲームを1行進めます。

advance
advance until screen "choice"

Exit link

Type: Command

exit

確認スクリーンを呼ばずにゲームを終了します。終了時にセーブしません。

if eval need_to_confirm:
    # Asks for confirmation, and autosaves if config.autosave_on_quit is True
    run Quit(confirm=True)

if eval persistent.quit_test_using_action:
    # Does not ask, but still autosaves if config.autosave_on_quit is True
    run Quit(confirm=False)

exit # neither asks nor autosaves

Pass link

Type: Command

pass

何もしません。空のテストケースように何もしないことができます。

testcase not_yet_implemented:
    pass

Pause link

Type: Command

pause [time (float)]

テスト実行を一定秒間停止します。Pause ステートメント に似ていますが、値が必要です。もしくは until 節を付ければ時間を指定しないことも可能です。

pause 5.0
pause until screen "inventory"

Run link

Type: Command

run <action>

提供された スクリーン言語アクション (またはアクションのリスト)を実行します。

提供されたアクション (またはリスト) を含むボタンが有効である場合に使用可能です。

testcase chapter_3:
    run Jump("chapter_3")

Skip link

Type: Command

skip [fast]

ゲームのスキップを開始します。 menu コンテキストの内部にいる場合はゲームに戻ってから開始し、それ以外の場合は単にスキップを開始します。

fast が指定されている場合、ゲームは直接次の選択肢にスキップします。

skip
skip fast
skip until screen "choice"

マウスコマンド link

Click link

Type: Command

click [button (int)] [selector] [pos (x, y)]

画面上で仮想のクリックを実行します。以下の任意のプロパティーを取ります :

  • button は、シミュレートされたマウスのどのボタンをクリックするかを指定します

    これは整数を取り、デフォルトは 1 です。 1 は左クリック、 2 は右クリック、 3 はミドルクリック、 4 と 5 は一部のマウスに見られる追加ボタンです。通常 Ren'Py は 1 と 2 にのみ反応はします。

selectorpos が指定されると、クリック送信前に仮想のテストマウスが move ステートメント のルールに従って動きます。

Click は パターン を受け取る節のように動作します。-taking clause which would not be given a pattern: pos が指定されないと、フォーカス可能な要素がない中間の場所を探します。

注釈

ゲームの会話を進めたい場合は、advanceskip のステートメントを使ってください。クリックでは、マウスの位置や画面上の内容によって予測不能な結果になりえます。

Drag link

Type: Command

drag <[selector] [pos (x, y)]> to <[selector] [pos (x, y)]> [button (int)] [steps (int)]

画面上でドラッグアクションをシミュレートします。以下のプロパティーを取ります :

  • ( to の前の) 最初の部分はドラッグの開始点を指定します。オプションで selectorpos プロパティーを取り、これらは move ステートメント のルールに従って解釈されます。

  • (to の後の) 2 番目の部分はドラッグの終点を指定します。同様にオプションの selectorpos プロパティーを取り、これらは move ステートメント のルールに従って解釈されます。

  • button は、仮想マウスのどのボタンをドラッグに使うかを指定します。整数を取り、デフォルトは 1 です。 1 は左クリック、 2 は右クリック、 3 はミドルクリック、 4 と 5 は一部のマウスに見られる追加ボタンです。通常、Ren'Py は 1 と 2 にのみ反応します。

  • steps は、ドラッグが取る中間ステップの数を指定します。整数を取り、デフォルトは 10 です。ステップが多いほどドラッグはスムーズになりますが、時間がかかります。

drag id "item_icon" to id "inventory_slot_3" button 1 steps 20
drag pos (100, 200) to pos (400, 500) button 1
drag id "item_icon" pos (0.5, 0.5) to pos (300, 400) steps 5
drag pos (50, 50) to id "inventory_slot_1"
drag pos (50, 50) to pos (150, 150)

Move link

Type: Command

move [selector] [pos (x, y)]

仮想のテストマウスを画面上の特定の位置に移動します。

selector が指定されかつ :

  • pos が指定されている場合、マウスはセレクターに対して相対的な指定の移動します。

  • pos が指定されていない場合、マウスはクリックすればそのセレクターにフォーカスするピクセルを探します。これは focus_mask のような要素も考慮に入れています。

selector が指定されず、かつ :

  • pos が指定されている場合、マウスは画面に対して相対的な指定位置に移動します。

  • pos が指定されていない場合はエラーが出されます。

# Move to a random clickable point within `back_btn`
move id "back_btn"

# Move to the center of `back_btn`
move id "back_btn" pos (0.5, 0.5)

# Move to a point 20 pixels right and 10 pixels down from the top-left corner of `back_btn`
move id "back_btn" pos (20, 10)

# Move to the top right corner of the screen
move pos (1.0, 0.0)

# Move to a point 20 pixels right and 10 pixels down from the top-left corner of the screen
move pos (20, 10)

Scroll link

Type: Command

scroll [amount (int)] [selector] [pos (x, y)]

スクロールイベントをシミュレートします。以下の任意のプロパティーを取ります :

  • amount は、スクロールする「ノッチ」の数を指定します。これは整数を取り、デフォルトでは 1 です。正の値は下にスクロールし、負の値は上にスクロールします。

  • selectorpos が指定されている場合、仮想テストマウスはスクロール送信前に move ステートメント のルールに従って移動されます。

scroll "bar"
scroll id "inventory_scroll"
scroll amount 10 id "inventory_scroll" pos (0.5, 0.5)
scroll # scrolls down at the current mouse position

注釈

これはマウスホイールイベントをシミュレートするのみです。 Screen Actions, Values および Functions の Scroll アクションの使用も検討できます

run Scroll("inventory_scroll", "increase", amount="step", delay=1.0)

キーボードコマンド link

Keysym link

Type: Command

keysym <keysym> [selector] [pos (x, y)]

キーシムイベントをシミュレートします。これには config.keymap のキーを含みます。

selectorpos が指定されている場合、仮想テストマウスが move ステートメント のルールに従って動かされ、その後キーシムが送信されます。

keysym "skip"
keysym "help"
keysym "ctrl_K_a"
keysym "K_BACKSPACE" repeat 30
keysym "pad_a_press"

Type link

Type: Command

type <string> [selector] [pos (x, y)]

指定の文字列をキーボードで入力したかのように入力します。

selectorpos が指定されている場合、仮想テストマウスが move ステートメント のルールに従って動かされ、その後テキストが送信されます。

type "Hello, World!"

コンディションステートメント link

コンディションは、ある条件が真かを検証するのに使われます。これらは ifassert, until といったコンディションを受け取るテストステートメントで使われます。

Boolean Values link

テストでは文字通りの真偽値 TrueFalse を利用できます。これらはいつでも準備できています。

if True:
    click "Start"

if False:
    click "Settings" # does not execute, since the condition is always false

Boolean Operations link

コンディションは notand, or 演算子をサポートします。式は括弧に含まれる場合もそうでない場合もあります

assert eval (renpy.is_in_test() and screen "main_menu")
advance until "ask her right" or label "chapter_five"
click "Next" until not screen "choice"

Eval link

Type: Condition

eval <expression>

提供された Python 式を評価します。これは assertif, until のようなコンディションを受け取られるテストステートメント内部での使用でのみ使われます。:

assert eval (renpy.is_in_test() and ("Ren'Py" in renpy.version_string))

注釈

$で始まる行と eval 節との違い :

  • Eval は単独で行に使えず、 ifuntil のようなステートメントの中に使う必要があります。一方、 $行 はそれぞれ独立した行に置かなければなりません。

  • $行は必ずしも値を持つわけではない任意の Python ステートメントを実行します(例えば $ import math など)。一方、 eval 節は返り値を必要とします。

Label link

Type: Condition

label <labelname>

テストステートメントが最後に実行された時点から、指定された Ren'Py ラベルに到達しているかを確認します。

以下の例を考えると :

run Jump("chapter_1")
assert label chapter_1 # works
assert label chapter_1 # fails

最初の assert ステートメントは、 run Jump("chapter_1") ステートメントによってラベル chapter_1 に到達したため機能します。2つ目の assert ステートメントは、最初の assert ステートメント以降、 chapter_1 というラベルに再び到達していないため失敗します。

つまり、以下の例は機能しません。

run Jump("chapter_1")
advance repeat 3
assert label chapter_1 # fails

警告

このテストステートメントを、 Ren'Py ネイティブの label ステートメントやスクリーンで使用される無関係な label要素 と混同しないようにしてください。

セレクターステートメント link

セレクターステートメントを使用してある要素が画面にあるかを確認して、さらにその要素を操作できます。

セレクターは特別な種類のコンディションです。

Displayable Selector link

Type: Condition, Selector

あるスクリーンまたは指定の id の要素が現在表示されているかを確認します。

パラメーターを一つ受け取り、そのスクリーンの名前です。次のプロパティーを受け取ります :

screen <name>

確認するスクリーンの名前です。

id <name>

確認する要素の id です。

layer <name>

そのスクリーンが表示されるレイヤーです。未指定ならそのレイヤーが自動的にスクリーン名から指定されます。

if screen "main_menu":
    click "Start"

advance until id "inventory_viewport" layer "overlay"

click "Close" until not id "close_button"

Text Selector link

Type: Condition, Selector

"<text>" [raw]

text セレクターは文字列を受け取り、スクリーン上のターゲットを見つけます。検索はスクリーン上のフォーカス可能なすべての要素(通常はボタンやメインテキストボックス)をすべて確認し、それらのテキストと alt テキスト) を確認して行われます。

この検索は大文字に区別されず、最も短いマッチを探します。例えば、文字列 "log" が指定され、スクリーンに "CATALOG""illogical" というテキストが含まれている場合、ターゲットは "CATALOG" のテキストとなります。

raw が指定されている場合、検索は翻訳と 補間 以前にスクリプトで指定されたテキストで処理されます。指定されない場合は、翻訳と補間の後にスクリーンに表示されるテキストそのままを検索します。

# This may be in a button
skip until "Start Game"

# This may be in the main textbox
advance until "Hey, that's not fair!"

# Case-insensitive search
assert "AsK HeR RighT AwaY"

# Search unsubstituted text
assert "Welcome, Eileen!"
assert "Welcome, [player_name]!" raw

# Search untranslated text after changing the language
run Language("japanese")
assert "スタート"
assert "Start" raw

コントロールステートメント link

これらのステートメントはテスト実行の流れを制御します。

Assert link

Type: Control

assert <condition> [timeout (float)] [xfail (bool)]

このステートメントはコンディションを受け取り、 asser ステートメントが実行された時点でそのコンディションが満たされない場合、 RenpyTestAssertionError を発生させます。

timeout が指定された場合、コンディションが満たされるまでその数秒間ステートメントは待ちます。その期間内にコンディションが満たされなければ、その assert は失敗します。

xfailTrue に設定されている場合、 assert ステートメントは失敗すると期待されます。これによりステートメントの意味が逆になり、コンディションが満たされれば assert は失敗し、コンディションが満たされなければ、 assert はパスします。

assert screen "main_menu"
assert eval some_function(args)
assert id "start_button" timeout 5.0

If link

Type: Control

if <condition>

このステートメントは、指定されたコンディションが満たされたときにテストステートメントのブロックを実行します。

if label "chapter_five":
    exit

if eval (persistent.should_advance and i_should_advance["now"]):
    advance

elifelse ステートメントを使用して、 if ステートメントに追加条件を加えられます。

if eval persistent.should_advance:
    advance
elif eval i_should_advance["now"]:
    advance
else:
    click "Start"

Repeat link

Type: Control

<command> repeat <number> [timeout (float)]

指定回数ステートメントを繰り返します。左側にコマンドステートメント、右側に repeat という単語で区切られた繰り返し回数で構成されています。

click "+" repeat 3
keysym "K_BACKSPACE" repeat 10
advance repeat 3

Screenshot link

Type: Command

screenshot <path> [max_pixel_difference (int or float)] [crop (x, y, width, height)]

現在の画面のスクリーンショットを撮り、指定されたパスに保存します。

  • path はスクリーンショットが保存される( _test.screenshot_directory に対する相対)パスを指定します。ファイル拡張子を含む場合もあります。サポートされているのは .png のみです。

  • max_pixel_difference は、テストが合格するために撮られたスクリーンショットと既存のスクリーンショットの間にどれだけピクセルが差をつけられるかを指定します。整数値はピクセル数を示し、浮動小数値はピクセル数の割合を示します。デフォルトは 0 です。

  • crop はスクリーンショットをトリミングする長方形を指定し、 (x, y, width, height) と表されます。座標は整数で指定しなければなりません。

プロジェクトがgitリポジトリにある場合、現在のコミットのハッシュが自動的にファイル名に付加されて @{hash}.png となります。これにより、開発者はスクリーンショットの変更を時間とともに追跡できます。

ファイルがすでにあれば、現在のスクリーンショットと既存のファイルを比較します。ファイルが max_pixel_difference ピクセル以上差があると、 RenpyTestScreenshotError が発生します。

既存のスクリーンショットを上書きするには、ファイルを削除するか、コマンドラインの --overwrite_screenshots オプションでテストを実行してください。

screenshot "screens/main_menu.png"
screenshot "screens/inventory" max_pixel_difference 0.01
screenshot "button.png" crop (10, 10, 100, 50)

これはパラメーター化されたテストで使用して複数のスクリーンショットを撮影できます

testcase screen_tester:
    parameter screen_name = ["inventory", "stats", "map"]

    run Show(screen_name)
    screenshot f"screens/{screen_name}.png"

Until link

Type: Control

<command> until <condition> [timeout (float)]

コンディションが満たされるまでステートメントを繰り返します。左側にコマンドステートメント、右側にコンディションステートメントが入り、 until という単語で区切られています。

右のコンディションが満たされた場合、次のステートメントに制御が移ります。そうでなければ、左のステートメントはコンディションが満たされるまで繰り返し実行されます。

timeout が指定された場合、コンディションが満たされるまでその数秒間ステートメントが続きます。その期間内にコンディションが満たされない場合、 RenpyTestTimeoutError が発生します。

このタイムアウトは、グローバルな _test.timeout 設定を一時的に上輪書きします。

advance until screen "choice"
click "Next"
advance until label "chapter_5"

skip until screen "inventory" timeout 20.0

Python ブロックと一行 Python link

python ブロック または 一行 python はテストケース内に追加できます。通常のRen'Pyコードとは異なり、Pythonブロックは in substore パラメーターを受け取りませんが、 hide キーワードを受け取ります。これら(両方)は、任意の Python コードの実行を可能にします。

init コードはテストが行われる前に実行されるため、 init python ブロックで定義された関数とクラスは、テスト Python ブロックとテストの一行 Python で呼び出せます。例えば

init python in test:
    def afunction():
        if renpy.is_in_test():
            return "test"
        return "not test"

testcase default:
    $ print(test.afunction()) # ends up in the console