Ideally, your system pushes this kind of "global" configuration down from the top of the supervision tree, rather than reading global state like this in a bunch of places. I would definitely encourage you to try and build your system with that in mind. Then, all of your tests can pass specific configuration to the part of the system under test, rather than relying on global state.
But as an alternative approach for your use case: you could implement a simple wrapper function around `System.get_env` (etc.) that reads/writes to a special key in the process dictionary, falling through to calling the `System` APIs if the process dictionary doesn't have the `:env` key (or whatever you want to call it).
Then, all you need to do in your tests, is store the env vars you want in the process dictionary of the test, and those will override the global `System` values.
Things get a bit trickier when spawning processes is involved, but there are various approaches for this (I believe ExUnit abuses these pretty heavily itself IIRC). One of them is to look at the ancestors of the current process until you either reach the root process, or you find one with the specified key in the process dictionary.
The reason why implementing this in ExUnit itself is likely to see pushback, is because there are just so many ways for this kind of global state to find its way into a program, and ExUnit cannot handle them all. Furthermore, I believe José wants to encourage good system design by making it harder to do things in a not-recommended way, i.e. in this case, not relying on global configuration deep inside your system. As a practical matter, it would also require adding the sort of wrapper code I mentioned to `System.get_env`, which isn't particularly palatable I would imagine.
Anyway, hope that helps/gives you some ideas!
Paul