Почему так много assertEquals()
или аналогичной функции принимают ожидаемое значение как первый параметр, а фактический - второй?
Это кажется мне интригующим, так есть ли особая причина этого необычного порядка?
Почему параметры assertEquals() в порядке (ожидаемые, фактические)?
Ответ 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
Это очень интересная тема, и здесь очень много образовательных ответов! Вот то, что я учусь у них:
-
Интуитивное/противо-интуитивное можно рассматривать как субъективное, поэтому независимо от того, в каком порядке оно было первоначально определено, возможно, 50% из нас не будут счастливы.
-
Лично я бы предпочел, чтобы он был задуман как
assertEqual(actual, expected)
, потому что, учитывая концептуальное сходство междуassert
иif
, я бы хотел, чтобы он следовал норме,if actual == expect
, например,if a == 1
.(PS: Это правда, что существуют разные мнения, которые побуждают писать оператор if в "обратном порядке", то есть,
if(1==a) {...}
, чтобы защитить вас от случайного пропуска одного=
. Но этот стиль был далек от нормы, даже в мире C/C++, и если вы пишете код на Python, вы не подвержены этой неприятной опечатке, потому чтоif a = 1
недопустимо в Python.) -
Практическая убедительная причина сделать
assertEqual(expect, actual)
заключается в том, что библиотека unittest на вашем языке, вероятно, уже следует этому порядку, чтобы генерировать читаемое сообщение об ошибке. Например, в Python, когда вы выполняетеassertEqual(expected_dictionary, actual_dictionary)
, unittest будет отображать недостающие ключи в фактическом с префиксом-
и дополнительные ключи с префиксом+
, как при выполненииgit diff old_branch new_branch
.Интуитивно понятный или нет, это единственная наиболее убедительная причина придерживаться
assertEqual(expected, actual)
. Если вам это не нравится, вам лучше принять это, потому что "практичность побеждает чистоту". -
И наконец, если вам нужен способ помочь вам запомнить порядок, этот ответ сравнивает
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");
(И есть другие причины, по которым я предпочитаю этот порядок, но для целей этого вопроса о том, почему он по-другому, рассуждения Кента кажутся ответом, даже если я его не понял.)