views:

110

answers:

2

I'm trying to run the following code with Ninject.Moq:

[TestMethod]
public void TestMethod1()
{
    var kernel = new MockingKernel();
    var engine = kernel.Get<ABC>();

   //as I don't need to actually use the interfaces, I don't want
   //to even have to bother about them.

    Assert.AreEqual<string>("abc", engine.ToString());
}

And here is the ABC class definition:

public class ABC {
    IA a;
    IB b;

    public ABC(IA a, IB b)
    {
        this.a = board;
        this.b = war;
    }

    public override string ToString()
    {
        return "abc";
    }
}

I'm getting the following exception:

System.ArgumentException: A matching constructor for the given arguments was not found on the mocked type. ---> System.MissingMethodException: Constructor on type 'AbcProxya759aacd0ed049f3849aaa75e2a7bade' not found.

+2  A: 

It's a bit like understanding DI in the first place :- small samples don't really get the whole point across.

An automocking container like Ninject.Moq (or similar test infrastructure libraries like AutoFixture) is hard to really explain with a simple example. I'd suggest reading all of Mark Seemann's posts on AutoFixture as a way of getting a feel fro the requirement.

So Ninject.Moq will deal with the chaining, N levels deep of a set of stub implementations of interfaces that are necessary to satisfy your System Under Test in the course of doing the thing your test is actually supposed to be testing.

In general, you want short easy to read, easy to grok tests with minimal complexity and interaction of fixtures under the cover (no big hierarchy of base classes, or 6 different magic methods doing wacky teardown and calling base classes). Normally this aim will mean you should keep your DI toolery miles away from your unit tests.

An automocking container should, like a chainsaw, only be used where you're going to get a signnificant real return (many shorter, easier to understand tests) for you investment (another tool to understand before others can read you tests, more debugging, more surprises, more complexity that'll lead to brittle, unmaintainable tests).

Ruben Bartelink
Thanks for the description. But given the example given, do you know if I'm doing something wrong?
devoured elysium
@devoured elysium: It is my belief that an automocking container should allow usage as you have above. AutoFixture certainly enables it (its what I use). To be honest, your question leaves me confused as to what bit is confusing/not working for you (or which of these describes your situation). ... hence a general response... Perhaps you could expand your question a bit and I'll either answer it, or stick a bounty on it and someone will be along in a flash with concrete examples of Ninject.Moq (if that's what you're looking for)
Ruben Bartelink
I edited the original post to be more explicit about what my problem currently is. In the meantime, I also posted the same question on Ninject's groups. If I get an answer there I'll post it here too.
devoured elysium
@devoured elysium: It's looking much better now. Is there anything interesting about IA and IB, i.e., should you put them in the snippet too? BTW this sample any use? http://markmail.org/message/pwy6y5h2gf4sfink
Ruben Bartelink
There is nothing interesting about IA and IB. I've only put them there to check that is possible to instantiate through Ninject.Moq the Abc class with those dependencies and still call its .ToString() method.
devoured elysium
In the example you gave (which I had been watching too, in the last hour) they seem to only use property injection, which is not of great help here.
devoured elysium
OK, looking at the exception itself.... It doesnt seem to relate to the IA or IB bit, its complaining about no def ctor on Abc. What happens if you put an `[Inject]` on the ctor? What happens if you put in a default ctor -- does it instantiate (I know that would defeat the purpose!)? Is it possible that Ninject.Moq is hardwired in some way that makes it work for prop injection and not for CI ? (AutoFixture doesnt require a default ctor and pretty sure DynamicProxy wouldnt have any underlying restrictions). Anyway, I'll stop guessing now. Go bounty!
Ruben Bartelink
I've tried property injection and it seems to work as expected. Trying to run it on an empty constructor seems to work fine, but setting the [Inject] attribute on the constructor doesn't seem to make a difference.
devoured elysium
@devoured elysium: It's not worth compromising your design (no, not in that tool vendor's sense!) to go PI instead of CI though. My initial scan of the source saw stuff about constructors. You should get an answer on the mailing list. If not, I suggest looking at the Ninject test suite - you'll quickly find appropriate examples of how to do the various underlying bits in Ninject.Moq in order to debug. (But if it was me, I'd go read about AutoFixture and use that)
Ruben Bartelink
So, from what the guys at the groups are saying, it seems Ninject.Moq only supports parameter injection :(
devoured elysium
@devoured elysium: So it saw (I keep a half an eye on it via RSS). Does the Rhino equivalent support CI? If so, it presumably uses DP under the cover and such usage could be ported?
Ruben Bartelink
I discovered what the problem was. I had to bind Abc to itself, otherwise it'd also get mocked and Moq only supports mocking parameterless classes, which was not the case.
devoured elysium
@devoured elysium: Congrats on resolving it and sorry for leading you on a wild goose chase!
Ruben Bartelink
+2  A: 

Ok, this will make the code work:

[TestMethod]
public void TestMethod1()
{
    var kernel = new MockingKernel();
    kernel.Bind<Abc>().ToSelf();
    var engine = kernel.Get<ABC>();

   //as I don't need to actually use the interfaces, I don't want
   //to even have to bother about them.

    Assert.AreEqual<string>("abc", engine.ToString());
}

One has to bind Abc to itself, otherwise it will also get mocked and Moq only supports mocking parameterless classes, which is not the case.

devoured elysium