tags:

views:

408

answers:

5

So I have the following class:

public class MyClass {
  internal void A() {
    foreach(Thing thing in ThingArray)
      B(thing);
  }

  virtual internal void B(Thing thing)
  {
    //  do some stuff
  }
}

And then I have the following test:

...
var testObject = new Mock<MyClass>(parameters);
testObject.Setup(t => t.B(It.IsAny<Thing>()));

test.Object.A();

test.Verify(t => t.B(It.IsAny<Thing>()), Times.Exactly(2));

And the verify is failing. I've checked, and the code is calling the real B() method as opposed to a mocked B() method.

I've got a lot of code running where Moq works perfectly, and I've been coding long enough to realize that I must be doing something wrong here, but for the life of me I can't see it. I've been proceeding under the assumption that since I'm calling test.Object.A(), the calls to B() are not going through the Mock, but that really doesn't make any sense to me since a call from any other object would work the same...

So why on earth isn't the mocked setup being executed?

Edit: Yes, I have the internals visible to the test project. I meant to put that into the original post, since I knew someone would mention it.

As to the real code, it is unfortunately VERY proprietary, so I can't post it. I'll see if I can adjust the code tomorrow to make it actually compile.

A: 

Hmm

Can you give us like a mini example of code that we can just pop in and run. I tried to take what you had and changed "Thing" to a string object but there is no t.B() that shows up so I don't know if something that you gave in the code has a typo or what. Since it does not show up in intellisene.

Also when I usually do my mocking I usually have a interface and I pass in that interface through my constructor. Like I am not sure how your actually passing this mock object to MyClass.

Since however I seen it you got to pass it in through like property injection, constructor inject or something like that. I never seen it where you don't pass it in or anything like that.

chobo2
+1  A: 

The object your Mock has to meet this criterias in order to make a successfully mock a method:

  • It has to be an interface
  • Or the method you want to mock has to be a virtual method and public.

Now you can also mock virtual-internal method, but in order to allow that you have to give Moq access to your internals. This you can do with:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

This make the internal accessible to the code-generator of Moq.

So in order to mock your MyClass.A call you have to do this:

  1. Make you method A virtual.
  2. And make your method public or allow access with [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

Or as said, make an interface which represents the API of MyClass.

Gamlor
A() is actually the method under test. Which is why I call test.Object.A() - I wanted to be able to test that particular method. I wanted to be able to test it without testing B(), which was why I ended up with the strange circumstances I have.I'm starting to think that my testing approach is flawed in this case, but I'm fairly new to this TDD thing...
Nathan
Thanks for the tip re: `DynamicProxyGenAssembly32`. Was pulling my hair out after adding an `InternalsVisibleTo("Moq")` and still getting nowhere :D
STW
A: 

Moq doesn't wrap the existing code, but instead creates an empty mock.

That means that calling testObject.Object.A() doesn't execute your original code, so B is never called.

If you pretend your mocking an interface then this makes sense because interfaces don't have code, so neither would the mock.

Cameron MacFarland
That's the odd thing... It is calling the original code. I tossed some exceptions into the A() and B() methods, and the exceptions were thrown. Also, wouldn't Moq create a derived class from the Mocked class? Which would mean that any non-virtual methods (like my example A()) would be called on the base class anyway. Or is the mocking done via reflection?... I don't think that would work since the mocked class would not be type-qualified as the original base class.
Nathan
+1  A: 

I'm not sure if Gamlor's answer works. It seems that if you want to perform a setup on a method where you want to verify that Class1.MethodA calls Class1.MethodB, MethodB (which is the one you would do the setup on) has to be public (regardless of InternalsVisibleTo). I wrote a simple test under a similar situation and found that once I made my MethodB public, Moq started working. I would bet if you made your method B public, it would work.

I assume this is a Castle or Moq bug but I don't know for sure. Hopefully somebody will chime in.

I know making MethodB public is not a good choice. But that is what I know about the situation...

jle
I did eventually determine the same thing; There are a number of other things that require public as opposed to "InternalsVisibleTo" - unfortunately in this case you don't get an error as much as you just get odd behavior.I ended up breaking the class into two pieces, which I suppose makes more sense; the public class is visible to the world, the second class is private and allows testing.
Nathan
A: 

Try creating the mock like this (I didn't try it so I don't know if it works):

var testObject= new Mock<MyClass> { CallBase = true };
bloparod