←back to thread

67 points ingve | 2 comments | | HN request time: 0.398s | source
Show context
BoiledCabbage ◴[] No.45950554[source]
The mock discussion still misses the real solution, which is to refactor the code so that you have a function that simple reads the file and returns json that is essentially a wrapper around open and doesn't need to be tested.

Then have your main function take in that json as a parameter (or class wrapping that json).

Then your code becomes the ideal code. Stateless and with no interaction with the outside world. Then it's trivial to test just like and other function that is simple inputs translated outputs (ie pure).

Every time you see the need for a mock, you're first thought should be "how can I take the 90% or 95% of this function that is pure and pull it out, and separate the impure portion (side effects and/or stateful) that now has almost no logic or complexity left in it and push it to the boundary of my codebase?"

Then the complex pure part you test the heck out of, and the stateful/side effectful impure part becomes barely a wrapper over system APIs.

replies(10): >>45950831 #>>45950929 #>>45951112 #>>45952380 #>>45952963 #>>45954934 #>>45958404 #>>45958469 #>>45960148 #>>45960154 #
tayo42 ◴[] No.45960154[source]
Your just moving the problem one layer up.

You still need to write a test for how it all comes together and you should write tests for your error handling. You need a mock to respond with an error.

replies(1): >>45967421 #
bccdee ◴[] No.45967421[source]
Not necessarily. If your error handling looks like this:

  value, err := externalLibraryFunctionFoo(a, b)
  if err != nil {
    return nil, fmt.Errorf("calling foo: %w", err)
  }
then you probably don't need to test it. All you're doing is bubbling up the error handling from other libraries' functions.
replies(1): >>45970009 #
1. tayo42 ◴[] No.45970009[source]
Tests help make sure that the intent is to just bubble up the error.

What if someone in the future is comes in and modifies that to add some complexity somehow or changes it to log and continue. Tests will catch that behavior

replies(1): >>45986258 #
2. bccdee ◴[] No.45986258[source]
It's rarely possible to future-proof a function by testing its entire range of possible inputs, so I'm not particularly concerned about trying to anticipate trivial cases that might become non-trivial in future—that just feels like a special case of future-proofing.

I think it's more important to ensure that, after each new commit, every non-trivial code path in that function is exercised. If someone adds new logic, they're responsible for adding new tests to cover that logic; similarly, if they turn a trivial code path into a non-trivial one, they're responsible for adding tests to cover that too.