web-dev-qa-db-ja.com

なぜassertEquals()パラメータが(期待される、実際の)順序であるのですか?

なぜそんなに多くのassertEquals()または同様の関数が期待値を最初のパラメーターとして受け取り、実際の値を2番目のパラメーターとして受け取るのですか?
これは私には直観に反しているように思えますが、この異常な順序に特別な理由はありますか?

59
jor

著者があなたの直感と一致する可能性が50%あったためです。

他の過負荷のため

assertWhatever(explanation, expected, actual)

そして、あなたが知っていることの一部である説明は、あなたがコードを書いたときにあなたが知らない実際のものとは対照的に、あなたが知っていることである期待されたものと一致します。

23
bmargulies

一貫性は#1であるというコンセンサスに同意しますが、辞書を比較する動作は、この質問を評価する場合に役立つデータポイントになる可能性があります。

差分に「+」が表示されると、「テスト対象の手順にこれが追加された」と読みました。繰り返しになりますが、個人的な好みが適用されます。

注:例をわかりやすくするために中央のキーだけが変更されるように、アルファベット順のキーを使用して辞書を長くしました。他のシナリオでは、より難読化された差分が表示されます。また注目に値する assertEqualはassertDictEqualを使用 > = 2.7および> = 3.1

exl.py

from unittest import TestCase


class DictionaryTest(TestCase):

    def test_assert_order(self):
        self.assertEqual(
            {
                'a_first_key': 'value',
                'key_number_2': 'value',
                'z_last_key': 'value',
                'first_not_second': 'value',
            },
            {
                'a_first_key': 'value',
                'key_number_2': 'value',
                'z_last_key': 'value',
                'second_not_first': 'value',
            }
        )

出力:

$ python -m unittest exl
F
======================================================================
FAIL: test_assert_order (exl.DictionaryTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "exl.py", line 18, in test_assert_order
    'second_not_first': 'value',
AssertionError: {'a_first_key': 'value', 'z_last_key': 'value', 'key_number_2': 'value', 'first_ [truncated]... != {'a_first_key': 'value', 'z_last_key': 'value', 'key_number_2': 'value', 'second [truncated]...
  {'a_first_key': 'value',
-  'first_not_second': 'value',
   'key_number_2': 'value',
+  'second_not_first': 'value',
   'z_last_key': 'value'}

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)
5
whp

XUnitテスト規約は期待された/実際のものです。だから、多くの人にとって、それは彼らが学んだことなので、自然な秩序です。

興味深いことに、xUnitフレームワークの規則からの脱却において、qunitは実際の/期待に応えます。少なくともjavascriptを使用すると、古い関数をカプセル化して新しい関数を作成し、それに元の変数を割り当てることができます。

var qunitEquals = equals;
equals = function(expected, actual, message) {
    qunitEquals(actual, expected, message);
};
2
Ed Sykes

これは非常に不快なトピックであり、非常に多くの教育的な答えもここにあります!これが私が彼らから学んだことです。

  1. 直感的/反直観的は主観的であると見なすことができるので、それが最初に定義された順序に関係なく、おそらく 50%の人は幸せではないでしょう

  2. 個人的には、assertifの概念的な類似性を考えると、それがassertEqual(actual, expected)として設計されていることを望んだでしょう if actual == expectの標準。たとえば、if a == 1

    (PS: ifステートメントを「逆の順序」で書くように求めるさまざまな意見があることは事実です。つまり、if(1==a) {...} を使用して保護します。誤って1つの=が欠落していることからです。しかし、そのスタイルは、C/C++の世界においても、標準からほど遠いものでした。そして、Pythonコードを記述している場合でも、そもそもその厄介なタイプミスに対して脆弱ではありません。 if a = 1はPythonでは無効であるためです。)

  3. assertEqual(expect, actual)を実行する実用的な説得力のある理由は、お使いの言語のユニットテストライブラリが、おそらくその順序に従って、読み取り可能なエラーメッセージを生成することです。たとえば、PythonでassertEqual(expected_dictionary, actual_dictionary)を実行すると、 unittestは、次の場合と同様に、実際に接頭辞-が付いた欠落キーと、接頭辞+ が付いた追加キーを表示しますgit diff old_branch new_branchを実行します。

    直感的かどうかにかかわらず、これがassertEqual(expected, actual)の順序を守る最も説得力のある理由の1つです。 "実用性は純粋さを上回っている" ので、それが気に入らない場合でも、それを受け入れるほうがよいでしょう。

  4. 最後に、順序を覚えやすくする方法が必要な場合、 この答えassertEqual(expected_result, actual_calculation)を割り当てステートメントの順序result = calculate(...)と比較します。それは事実上の行動を覚えるのに良い方法ですが、私見それはその順序の議論の余地のない推論がより直感的ではありません。

だからここに行きます。幸せassertEqual(expect, actual)

2
RayLuo

answer from Kent Beck は、SUnitとJUnit(おそらくこの規約の起源)の作成者です。

一連のassertEqualsを続けて並べます。最初に期待することで、彼らはよりよく読むことができます。

しかし、これは私自身の経験とは正反対なので、誤解しているのではないかと思います。これは私がテストでよく目にするものです:

assertEquals(12345, user.getId());
assertEquals("kent", user.getUsername());
assertEquals("Kent Beck", user.getName());

私はこれがactualの値を最初に読む方が読みやすいと思います。これにより、反復的な定型文がさらにまとめられ、値をテストするメソッド呼び出しが調整されます。

assertEquals(user.getId(), 12345);
assertEquals(user.getUsername(), "kent");
assertEquals(user.getName(), "Kent Beck");

(そして私がこの順序を好む理由は他にもありますが、なぜについてのこの質問の目的のため、それは逆の方法です、ケントの推論は理解していなくても、答えてください。)

1
Chris Povirk

assertEqual()の潜在的な目的は、人間の読者のためにコードをデモすることです。最も単純な関数呼び出しはresult = function(parameters)なので、左側の戻り値右側の呼び出しを考えることに慣れます。

したがって、関数を文書化するテストでは、左側にリテラルが表示され、右側に呼び出しが表示されます。

assertEqual(15, sum((1,2,3,4,5)))

つまり、(予想、実際)。同様に式で。

assertEqual(4, 2 + 2)
1
Bob Stein