Why are assertEquals() parameters in the order (expected, actual)?

前端 未结 7 1803
余生分开走
余生分开走 2021-01-31 01:28

Why do so many assertEquals() or similar function take the expected value as first parameter and the actual one as second ?
This seems counter-intuitive to me,

相关标签:
7条回答
  • 2021-01-31 01:31

    An ulterior purpose of assertEqual() is to demo code for human readers. Because the simplest function call is result = function(parameters), one gets used to thinking of the return value on the left and the call on the right.

    So a test that documents a function would show a literal on the left and a call on the right.

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

    That is, (expected, actual). Similarly with an expression.

    assertEqual(4, 2 + 2)
    

    If you like lining things up (PEP8 notwithstanding), the expected parameter helps being shorter on the left:

    assertEqual(42, 2 * 3 * 7)
    assertEqual(42, (1 << 1) + (1 << 3) + (1 << 5))
    assertEqual(42, int('110', int('110', 2)))
    

    Thanks Andrew Weimholt and Ganesh Parameswaran for these formulae.

    0 讨论(0)
  • 2021-01-31 01:41

    The answer from Kent Beck, creator of SUnit and JUnit (where possibly this convention originates), is:

    Line a bunch of assertEquals in a row. Having expected first makes them read better.

    However, this is so opposite to my own experience that I have to wonder if I'm misunderstanding it. Here's what I often see in tests:

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

    I would think this would read better with the actual value first. That puts more of the repetitive boilerplate together, aligning the method calls whose values we're testing:

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

    (And there are other reasons that I prefer this order, but for the purpose of this question about why it's the other way, Kent's reasoning appears to be the answer, even if I haven't understood it.)

    0 讨论(0)
  • 2021-01-31 01:42

    The explanation I heard is that it comes from TDD.

    In Test Driven Development, you start with the test, and then write the code.

    Starting assertions by writing the expectation, and then call the code that should produce it, is a mini version of that mindset.

    Of course, this may just be a story people tell. Don't know that it was a conscious reason.

    0 讨论(0)
  • 2021-01-31 01:45

    This is a very intesting topic, and lots of very educational answers here too! Here is what I learn from them:

    1. Intuitive/counter-intuitive can be considered as subjective, so no matter which order it was originally defined, perhaps 50% of us would not be happy.

    2. Personally I would have preferred it were designed as assertEqual(actual, expected), because, given the conceptual similarity between assert and if, I would wish it follows the norm of if actual == expect, for example, if a == 1.

      (PS: It is true that there are different opinions which prompts to write if statement in the "reverse order", i.e. if(1==a) {...}, in order to guard you from accidentally missing one =. But that style was far from the norm, even in the C/C++ world. And if you happen to be writing Python code, you are not vulnerable to that nasty typo in the first place, because if a = 1 is not valid in Python.)

    3. The practical convincing reason to do assertEqual(expect, actual), is that the unittest library in your language likely already follows that order to generate readable error message. For example, in Python, when you do assertEqual(expected_dictionary, actual_dictionary), unittest will display missing keys in actual with prefix -, and extra keys with prefix +, just like when you do a git diff old_branch new_branch.

      Intuitive or not, this is the single most convincing reason to stick with the assertEqual(expected, actual) order. If you happen to not like it, you better still accept it, because "practicality beats purity".

    4. Lastly, if you need a way to help you remember the order, this answer compares assertEqual(expected_result, actual_calculation) to the assignment statement order result = calculate(...). It can be a good way to MEMORIZE the de-facto behavior, but IMHO it is not the undebatable reasoning of that order is more intuitive.

    So here you go. Happy assertEqual(expect, actual) !

    0 讨论(0)
  • 2021-01-31 01:45

    The xUnit testing convention is expected/actual. So, for many that is the natural order since that's what they learnt.

    Interestingly in a break from convention for an xUnit framework qunit goes for actual/expected. At least with javascript you can just create a new function that encapsulates the old one and assign it the original variable:

    var qunitEquals = equals;
    equals = function(expected, actual, message) {
        qunitEquals(actual, expected, message);
    };
    
    0 讨论(0)
  • Because the authors had a 50% chance of matching your intuition.

    Because of the other overload

    assertWhatever(explanation, expected, actual)
    

    And the explanation, which is part of what you know, goes with the expected, which is what you know, as opposed to the actual, which you don't know at the time you write the code.

    0 讨论(0)
提交回复
热议问题