A co-worker was reviewing some of my unit-test code on some string generation, which kicked off a lengthy discussion. They said that the expected results should all be hard-coded and was worried that a lot of my test cases were using what was being tested to test against.
Lets say there is simple function that returns a strings with some arguments.
generate_string(name, date) # Function to test
result 'My Name is {name} I was born on {date} and this isn't my first rodeo'
----Test----
setUp
name = 'John Doe'
date = '1990-01-01'
test_that_generate_string_function
...
expected = 'My Name is John Doe I was born on 1990-01-01 and this isn't my first rodeo'
assertEquals(expected, actual)
My co-worker was instant that the expected result should always be hard-coded, as it stops there being any chance that the actual result can influence the expected result.
test_date_hardcoded_method
...
date = 1990-01-01
actual = generate_string(name, date)
expected = 'My Name is John Doe I was born on 1990-01-01 and this isn't my first rodeo'
So if they want to make sure that the date is all up to snuff they would pass in a date value and hard-code the expected result. To me this makes sense but also seems competently redundant. The function already has a test to make sure the entire string is as expected. Any deviation from that is going to result in failed test. My method was to take the actual result, deconstruct it, hard-code something specific, and throw it back together to be used as the expected result.
test_date_deconstucted_method
...
date = get_date()
actual = generate_string(name, date)
actual_deconstructed = actual.split(' ')
actual_deconstructed[-7] = '1990-01-01' # Hard code small expected change
expected = join.actual_deconstructed
assertEquals(expected, actual)
I ended up creating two test units using each method to see if I could understand where they were coming from but I just don't see it. When all of the expected results are hard-coded any little change makes the vast majority of the tests to fail. If "isn't" needs to be "is not" the hardcoed_method is going to fail until someone manually changes things. Whist the deconstructed_method only cares about the date and will still pass it's test. It will only fail if something unexpected happens to the date. With only a few tests failing after a change someone else has made it's really easy to pinpoint exactly what's gone wrong, which I thought was the whole point of unit testing.
I'm still within my first month of my first programming job. My co-worker is vastly more experienced than me. I have zero conviction in myself and normally just accept other people's opinions as truths, but this makes so much more sense to me. I understand their thought that having expected results informed from the actual results can be bad, but I trust all the other tests to form a web of informing tests. String formatting, token values, and formatting are all covered, as well as hard-coded tests that check for any incorrectness.
Should every test's expected results be hard-coded? Is it bad to use the actual results to inform expected results once the groundwork has already been tested?