Подтвердить что ты не робот

Почему параметры assertEquals() в порядке (ожидаемые, фактические)?

Почему так много assertEquals() или аналогичной функции принимают ожидаемое значение как первый параметр, а фактический - второй?
Это кажется мне интригующим, так есть ли особая причина этого необычного порядка?

4b9b3361

Ответ 1

Потому что у авторов была 50% вероятность совпадения вашей интуиции.

Из-за другой перегрузки

assertWhatever(explanation, expected, actual)

И объяснение, которое является частью того, что вы знаете, идет с ожидаемым, что вы знаете, в отличие от фактического, которое вы не знаете в момент написания кода.

Ответ 2

Я согласен с консенсусом, что согласованность является # 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)

Ответ 3

Ожидается/актуально соглашение о тестировании xUnit. Таким образом, для многих это естественный порядок с тех пор, что они узнали.

Интересно, что в перерыве от конвенции для xUnit framework qunit идет для фактического/ожидаемого. По крайней мере, с помощью javascript вы можете просто создать новую функцию, которая инкапсулирует старую и назначит ей исходную переменную:

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

Ответ 4

assertEqual() целью assertEqual() является демонстрация кода для читателей-людей. Поскольку простейшим вызовом функции является result = function(parameters), мы привыкли думать о возвращаемом значении слева и вызове справа.

Таким образом, тест, который документирует функцию, будет показывать литерал слева и вызов справа.

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

То есть (ожидаемый, актуальный). Аналогично с выражением.

assertEqual(4, 2 + 2)

Ответ 5

Это очень интересная тема, и здесь очень много образовательных ответов! Вот то, что я учусь у них:

  1. Интуитивное/противо-интуитивное можно рассматривать как субъективное, поэтому независимо от того, в каком порядке оно было первоначально определено, возможно, 50% из нас не будут счастливы.

  2. Лично я бы предпочел, чтобы он был задуман как assertEqual(actual, expected), потому что, учитывая концептуальное сходство между assert и if, я бы хотел, чтобы он следовал норме, if actual == expect, например, if a == 1.

    (PS: Это правда, что существуют разные мнения, которые побуждают писать оператор if в "обратном порядке", то есть, if(1==a) {...}, чтобы защитить вас от случайного пропуска одного =. Но этот стиль был далек от нормы, даже в мире C/C++, и если вы пишете код на Python, вы не подвержены этой неприятной опечатке, потому что if a = 1 недопустимо в Python.)

  3. Практическая убедительная причина сделать assertEqual(expect, actual) заключается в том, что библиотека unittest на вашем языке, вероятно, уже следует этому порядку, чтобы генерировать читаемое сообщение об ошибке. Например, в Python, когда вы выполняете assertEqual(expected_dictionary, actual_dictionary), unittest будет отображать недостающие ключи в фактическом с префиксом - и дополнительные ключи с префиксом +, как при выполнении git diff old_branch new_branch.

    Интуитивно понятный или нет, это единственная наиболее убедительная причина придерживаться assertEqual(expected, actual). Если вам это не нравится, вам лучше принять это, потому что "практичность побеждает чистоту".

  4. И наконец, если вам нужен способ помочь вам запомнить порядок, этот ответ сравнивает assertEqual(expected_result, actual_calculation) с result = calculate(...) порядка присваивания: result = calculate(...). Это может быть хорошим способом ЗАПОМНИТЬ де-факто поведение, но ИМХО это неоспоримое рассуждение о том, что порядок более интуитивен.

Итак, поехали. Happy assertEqual(expect, actual) !

Ответ 6

Ответ от Кента Бека, создателя SUnit и JUnit (где, возможно, возникла эта конвенция):

Выровняйте связку assertEquals подряд. Ожидание сначала заставляет их читать лучше.

Тем не менее, это настолько противоречит моему собственному опыту, что я задаюсь вопросом, неправильно ли я это понимаю. Вот что я часто вижу в тестах:

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

Я думаю, что это будет лучше читать с фактическим значением в первую очередь. Это объединяет больше повторяющихся шаблонов, выравнивая вызовы методов, значения которых мы тестируем:

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

(И есть другие причины, по которым я предпочитаю этот порядок, но для целей этого вопроса о том, почему он по-другому, рассуждения Кента кажутся ответом, даже если я его не понял.)