Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PrivateObject wont return out parameter

I'm trying to test private methods in a Unit test project. So far it's going great, but I hit a bump, when I have to test a method with an out parameter. The signature for that method is:

private bool GotSSI(out SSI ssi, RSI rsi)
{
        ~code omitted~
}

And the unittest (the part that is not working) looks like this:

SSI ssi = null;
object[] p = new object[]{ssi,rsi};
Type[] t = new Type[] { typeof(SSI).MakeByRefType(), typeof(RSI) };
actual = (bool) privateTarget.Invoke("GotSSI",t,p);

The GotSSI method work. I've tested it in debug mode within the unit test and I can see that the 'ssi' out variable is set inside the method, before returning it's true or false value. But when the test returns to it's own code, the 'ssi' variable is still null. So the problem is that the object I created in the "GotSSI" method, is not parsed out of the PrivateObject invoke method.

Anyone knows what I am missing?

Update (Solution by Rafal)

Rafal's solution work perfectly and here is how I implemented the solution.

I created a delegate:

delegate bool GotSSIInternal(out SSI ssi, RSI rsi);

And when I have created the object I wanted to test, I build the delegate (target is the object i'm testing):

GotSSIInternal gotSSIInternal = (GotSSIInternal) Delegate.CreateDelegate(
            typeof (GotSSIInternal), 
            target,
            typeof(OfflineResolver).GetMethod("GotSSI", BindingFlags.NonPublic | BindingFlags.Instance));

After that is very simple to call the delegate:

actual = gotSSIInternal.Invoke(out ssi, rsi);

The solution is very simple and works like a charm.

like image 503
evilfish Avatar asked Jan 08 '13 11:01

evilfish


2 Answers

Although the final solution that was accepted works, there is a much simpler way to do it. If you follow the link given in the accepted answer from Rafal, you will find a similar question to this one, with two answers. The second answer (with the most "useful" points) is the simpler of the two.

Here is a modified version of that answer specifically for a testing scenario:

//method to test is a private method of the class ClassTotest with signature 
//    TryGetCustomerData(List<Invoice> invoices, out CustomerData customerData) 
//set up
var objToTest = new ClassToTest();
var invoices = GetInvoices();
CustomerData customerData = null;

//set up the arguments
var args = new object[] { invoices, customerData };
//get the MethodInfo of the method you want to test
var method = typeof(ClassToTest).GetMethod("TryGetCustomerData",
    BindingFlags.NonPublic | BindingFlags.Instance);
//invoke it
var success = (bool)method.Invoke(objToTest, args);
//get back the customerData argument - the "out" parameter
var actual = args[1] as CustomerData;
like image 135
grahamesd Avatar answered Sep 19 '22 03:09

grahamesd


your invocation of method with out parameter is wrong if you want to get the out value. See this on how to invoke it with reflection.

like image 36
Rafal Avatar answered Sep 20 '22 03:09

Rafal