Use reflection to set the return type of a private method

59 Views Asked by At

I've been tasked with writing unit tests for poorly authored legacy code. The code that I should write tests for can't get changed in any way whatsoever. It's READ-ONLY.(Company policy, don't touch this!)

Please look at the example below:

//This class can't be changed or refactored. It is what it is.
public class OldUntouchableCode
{
    public string DoStuff()
    {
        var result = DoInternalStuff();
        return result + " new stuff";
    }

    private string DoInternalStuff()
    {
        //Making external calls that DON'T use the dependency-injected clients.
        //This means that the external calls can't be mocked.
        //The output of this call changes depending on what the external call returns.
        //This makes the return value of this method unpredictable.
        var client = new HttpClient();
        /*
         * imagine a bunch of code here that uses the HttpClient to make external calls
         */
        return "The result of the external calls";
    }
}

OldUntouchableCode represents the code that I must write tests for. The DoStuff public method uses the DoInternalStuff private method to perform its job. However, this private method makes external calls that can't get mocked.

Trying to write tests for this code results in the following situation:

var sut = new OldUntouchableCode();
//I need to set the return value of DoInternalStuff() to a specific value, so I can test the DoStuff() method.
//This test might or might not pass, depending on what the external call returns. This return value is unpredictable.
var actual = sut.DoStuff();
var expected = "expected value new stuff";

Console.WriteLine($" Test {(expected == actual ? "Passed":"Failed")}");

Since the DoInternalStuff method behaves in an unpredictable manner, the output of the DoStuff method can't get tested reliably.

To be perfectly clear, I'm NOT trying to test the private method.

I've discovered already that I can find this private method's MethodInfo with reflection:

var methodInfo = sut.GetType().GetMethod("DoInternalStuff", BindingFlags.NonPublic | BindingFlags.Instance);

The above code successfully captures the MethodInfo of the DoInternalStuff private method. I can see in the debugger that this object contains the correct name of this method.

At this stage, I need a way to tell the runtime to return a specific value(that I determine) from the DoInternalStuff private method on this instance of the OldUntouchableCode no matter what the external call returns.

In other words, I need to tell the runtime: "Listen! When I run sut.DoStuff(), you will eventually invoke the DoInternalStuff method. When you do so, return THIS particular string from that method, no matter what occurs inside of that method."

Is this goal possible to achieve?

1

There are 1 best solutions below

1
Squirrelkiller On

As far as I know this is unfortunately impossible, and if you can't modify the internal HttpClient, things are gonna get complicated.

The only way you could modify the internally executed request might be the framework event, but this is too complicated for me to understand how possible this is.

Probably easier would be to choose some heuristic for what can be returned.

For example, a method getting the current IP address by querying whois.com will return a different IP address depending on which machine runs it.

You could however check whether or not the returned value is in the correct format for an IP address instead.

For a method querying the current city, you could make a list of possible cities a CI/CD runner or developer might be in and check if the result is included in the list.

Go up a level of abstraction, find out what the method always returns (like "the current city" or "a link-local IPv6 address", and test that.