Mocking an object with Moq, using Ninject when doing UnitTesting
Asked Answered
P

1

7

I'm having trouble using Moq in a UnitTesting project with Ninject.

First a few lines about my solution. It contains several projects (BussinesLogic, DAL, Infrastructure...). My goal is to UnitTest the logic i'm using in BussinessLogic project. The solution is basicly for a windows service, but i've put in the logic so it can be run standalone. I'm using Ninject and i specify weather i want to use the ProductionModule or the TestingModule (windows service uses ProductionModule, console app uses TestingModule)

I'm using a factory pattern to get ninject kernel whenever i need it inside my application.

My TestingModule inherits from NinjectModule where i override the Load() method and there i do the binding. For instance:

Bind<IStorageManager>().To<StubStorageManager>();

I have the StubStorageManager but it's empty. It contains just the declaration of methods from IStorageManager.

The thing i would like to do is (in laymans terms): Create a unitTest where i would create a new kernel specifying the TestingModule as it's parameter. Then i would like to create a mock object (let's say a mock of IStorageManager) storageManagerMock. Some method in IStorageManager returns a messageObject so i would probably need to mock that too, couse the bussiness logic is doing something based on that messageObject. So i would like to somehow set properties to that message object and then call some businessLogic method on it, so i can see if the logic works correctly.

I hope i didn't complicate it too much.

Please bear with me, i'm completely new to mocking and dependency injection, but am willing to learn.

Pathway answered 29/4, 2011 at 13:4 Comment(1)
Possible duplicate: https://mcmap.net/q/50173/-using-ioc-for-unit-testingEpistrophe
F
12

I doubt you really want to be using Ninject in your tests. The whole point of using ninject is that you can decouple everything. You also want to try and keep everything decoupled from the dependency container itself if possible. Pass it in if you have to, or pass in factories that create the required object and have the container pass in the factory.

I suspect you probably want to do something like this:

public void ATest(){
   //create a mock StorageManager
   var managerMock = new Mock<IStorageManager>();
   //create a mock MessageObject to be used by business logic
   var messageObjectMock = new Mock<MessageObject>();

   //have the storage manager return the mock message when required
   managerMock.Setup(x => x.GetMessageObject()).Returns(messageObjectMock.Object);
   //set up message expectations
   messageObjectMock.Setup(x => x.ThisValueExpected).Returns(10);
   messageObjectMock.Setup(x => x.ThisFunctionShouldBeCalled()).Verifiable("Function not called.");

   //thing to test
   BusinessLogicObject blo = new BusinessLogicObject(managerMock.Object);
   blo.DoTheThingImTesting();

   //make sure the business logic called the expected function, or do whatever check you need...
   messageObjectMock.Verify();
 }
Featherweight answered 29/4, 2011 at 14:0 Comment(2)
This is exactly what i wanted to do. Ok, so using a DI container in test is bad i take it? Why is that so? I thought that by using it, it might simplify my tests so i dont have to write: var p = new Program(new StubHealthMonitor(), storageManagerMock, new LogManager(), new StubConfigurationManager()); I basicly thought that i would let the DI container take care of all the things that don't directly involve this test, but the one thing that does involve the test, i could specify on my own via Moq.Pathway
I'm not sure I'd go so far as saying using DI in testing is "bad". Sub-optimal maybe ;) The thing you want to do with your tests is to remove as much external 'stuff' as possible and only use the thing you are testing. If you use DI in your tests you now have the added complexity of your dependency injection. At that point you are in effect testing your DI as well as the thing under test. You might be able to make a case for using DI in your tests although I've never needed to yet. When using DI nothing should be tightly coupled to anything - including the DI so you shouldn't need it.Featherweight

© 2022 - 2024 — McMap. All rights reserved.