views:

135

answers:

2

We have a VB.net function with the following signature in class InitializerFactory:

Public Shared Function Create(ByRef ui As Object) As IModeInitializer

I'm attempting to test this function by passing in a mock of ui (using Rhino Mocks):

MainForm ui = mocks.StrictMock<MainForm>();
IModeInitializer item = InitializerFactory.Create(ref ui);

When attempting to pass ui as a parameter, I get the following errors:

  • The best overloaded method match for 'InitializerFactory.Create(ref object)' has some invalid arguments
  • Argument '1': cannot convert from 'ref MainForm' to 'ref object'

Ideally, the solution would be to extract an interface on UI (or its class, MainForm) but that's not doable by any means - it's an extremely bloated class.

I also can't declare ui as an Object, or else I can't mock the methods inside of it since the methods don't belong to an Object type.

My question is -- what am I doing wrong?

+3  A: 

This is just because of the ref parameter syntax. The problem is that the function has to be able to set ANY type of object, since it's a by ref parameter. You can't just pass it a reference to a MainForm, which is what you're attempting.

Unfortunately, this is a pretty difficult API to work with.

You can handle this by assigning your instance to an object first:

MainForm ui = mocks.StrictMock<MainForm>();
object uiObj = ui;
IModeInitializer item = InitializerFactory.Create(ref uiObj);
if (uiObj != ui) { 
    // Handle the case where the reference changed!
    ui = uiObj as MainForm; // May be null, if it's no longer a "MainForm"
}

If you want to fully understand this, you can read up on Covariance and Contravariance.

Reed Copsey
I've tried this, but then I get the following error in NUnit:**System.InvalidOperationException : The object '' is not a mocked object.** I'm assuming that it's talking about the uiObj since it's not just an Object as opposed to a mock object.
MunkiPhD
It would really help if you'd say where that error occurred. But I agree with Reed - it sounds like a horrible API. Does it really have to have a by-ref parameter?
Jon Skeet
@MunkiPhD: That's not the problem. Casting and assigning to object doesn't change the actual type of object. You have some other issue going on inside of the method.
Reed Copsey
Yea, the API isn't the greatest in some areas, but 'it is what it is.'
MunkiPhD
+1  A: 

This is a duplicate of:

http://stackoverflow.com/questions/1207144/c-why-doesnt-ref-and-out-support-polymorphism/1207302#1207302

I answered that question a couple weeks ago on my blog. Here's a link:

http://blogs.msdn.com/ericlippert/archive/2009/09/21/why-do-ref-and-out-parameters-not-allow-type-variation.aspx

Eric Lippert
So to my understanding, there's no real way I can go about mocking the MainForm class?
MunkiPhD
I don't understand why you've come to that conclusion. The variable passed to the method must be of type object. The reference in that variable can be of type MainForm. If you want a second variable of type MainForm that contains the same reference, just make another variable.
Eric Lippert