3

common testerlang のテスト フレームワークとして使用し始めています。

正の数のみを受け入れると予想される関数があり、それ以外の場合は吹き飛ばされるとします。

positive_number(X) when > 0 -> {positive, X}.

そしてそれをテストしたい

positive_number(-5).

正常に完了しません。

この動作をテストするにはどうすればよいですか? 他の言語では、テスト ケースは何らかのエラーまたは例外を想定しており、テスト対象の関数が無効な無効なパラメーターに対してエラーをスローしない場合は失敗します。共通テストでそれを行う方法は?

アップデート:

私はそれを動作させることができます

test_credit_invalid_input(_) ->
  InvalidArgument = -1,
  try mypackage:positive_number(InvalidArgument) of
    _ -> ct:fail(not_failing_as_expected)
  catch
    error:function_clause -> ok
  end.

しかし、これは冗長すぎると思います。次のようなものが欲しいです:

assert_error(mypackage:positive_number, [-1], error:function_clause)

一般的なテストのどこかにこれがあり、フレームワークに関する適切な知識が不足しているため、このような冗長なソリューションを採用していると思います。

更新: Michael の応答に触発されて、次の関数を作成しました。

assert_fail(Fun, Args, ExceptionType, ExceptionValue, Reason) ->
  try apply(Fun, Args) of
    _ -> ct:fail(Reason)
  catch
    ExceptionType:ExceptionValue -> ok
  end.

そして私のテストは次のようになりました:

test_credit_invalid_input(_) ->
  InvalidArgument = -1,
  assert_fail(fun mypackage:positive_number/1,
              [InvalidArgument],
              error,
              function_clause,
              failed_to_catch_invalid_argument).

しかし、すべてのテストケースでassert_fail呼び出しを行うよりも、呼び出しを行う方が少し読みやすいので、うまくいくと思います。try....catch

Common Test にはよ​​り良い実装が存在するはずだと私はまだ考えています。IMO は、このテスト パターンをすべてのプロジェクトで繰り返し実装するのは醜い繰り返しです。

4

1 に答える 1

3

例外を式に変換して一致させます。

test_credit_invalid_input(_) ->
    InvalidArgument = -1,
    {'EXIT', {function_clause, _}}
            = (catch mypackage:positive_number(InvalidArgument)).

これにより、おそらく期待できるほど簡潔な方法で、例外が非例外に、またはその逆になります。

冗長性を隠すために、いつでもマクロまたは関数を使用することもできます。

編集 (re: コメント):

質問のように、完全な try catch コンストラクトを使用すると、失敗のケースに関する情報が失われます。その情報は、アトム「not_failing_as_expected」または「failed_to_catch_invalid_argument」を優先して破棄されるためです。

シェルで予想される失敗値を試す:

1> {'EXIT', {function_clause, _}}
        = (catch mypackage:positive_number(-4)).             
{'EXIT',{function_clause,[{mypackage,positive_number,
                                 [-4],
                                 [{file,"mypackage.erl"},{line,7}]},
                      {erl_eval,do_apply,6,[{file,"erl_eval.erl"},{line,661}]},
                      {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,434}]},
                      {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,441}]},
                      {shell,exprs,7,[{file,"shell.erl"},{line,676}]},
                      {shell,eval_exprs,7,[{file,"shell.erl"},{line,631}]},
                      {shell,eval_loop,3,[{file,"shell.erl"},{line,616}]}]}}

シェルでの期待される成功値のトゥルーイング:

2> {'EXIT', {function_clause, _}} = (catch mypackage:positive_number(3)). 
** exception error: no match of right hand side value {positive,3}

どちらの場合も多くの情報を得ることができますが、重要なことに、どちらの場合も、テスト対象の関数を呼び出すために使用されたパラメーターを知ることができます (ただし、2 番目のケースでは、これは関数が確定的で 1 対 1 であるためです)。

このような単純なケースでは、これらのことはそれほど重要ではありませんが、原則として重要です。後で、関数が失敗する値がここのようにハードコードされていない可能性があるより複雑なケースでは、関数の失敗の原因となった値、または戻り値がわからない。これは、見苦しいバックトレースを 1 ~ 2 回見て問題が何であるかを正確に理解するか、15 分かけてテストをセットアップして実際に何が起こっているかを調べるかの違いになる可能性があります... または、さらに悪いことに、それがheisenbugを探すのに何時間も費やすかもしれません!

于 2015-11-15T21:37:23.257 に答える