Use the most simple and shortest approach, which is in Python probably option A, monkey patching. Everything else makes the code more complicated, with almost no benefit.
Converting your module to a class (option C) should be motivated by the fact you need a class instead of a module, not by the fact you want to mock a single function. Same argument holds for replacing the method do_something by an object with a method (option D). So this leaves you with option B or A. But I would not pollute the parameter list of func for the purpose of mocking, nor would I stuff technical setup code into a function func just for the purpose of mocking if there is simpler alternative. Better keep the "official" API as as well the "business code" as clean as possible. Imagine what happens if you want to mock more "private" methods instead of just one, and if you want to test 5 public methods of the module - the API will contain 90% parameters only used for testing, which decreases the readability by a magnitude.
If you have concerns about the monkey patching approach because it manipulates something private, you can add a public "patching function" to the module, which allows the manioulation to be done through a "public" function:
def setup_mock_for_do_something(do_something): _do_something = do_something This makes the possibility of "monkey patching" in this module more explicit, by simultanously avoiding unneccessary structural changes to the whole code.