←back to thread

67 points ingve | 1 comments | | HN request time: 0s | 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 #
1. bccdee ◴[] No.45960148[source]
I think the important thing is that the code look pure from a testing perspective.

Say you've got a function that accesses a key-value store. Ideally, you can factor out the i/o so that you do all your reads up front and all your writes at the end, leaving a pure function in the middle. But if the code is too tangled up in its side effects for that, the next best thing is to create a fake KV store and then wrap the function like this:

  def doTest(input, initialState):
    kv = makeFake(initialState)
    result = doThing(kv, input)
    return result, kv.dumpContents()
doThing isn't a pure function, but doTest is. Now you can write tests like this:

  result, outputState = doTest(input, initialState)
  assert (result, outputState) == expected
I guess you could call that "imperative core, functional shell," lol.