Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting Mocks on large dependency object graph

I have a a fairly significant dependency graph for an object I want to test. What is the easiest way to resolve my dependencies without having to register mocks everywhere?

For example, I have a dependency graph like this:

  PublicApi
    ApiService
      AccountingFacade
         BillingService
           BillingValidation
           BillingRepository
         UserService
           UserRepository

I want to test PublicApi.CreateUser(), and I want it to run through all the code, but I want to mock the repositories so I don't have to write anything to the database. Should I just use a DI container and register all my services, replacing the repositories with mocks, then resolve PublicApi and run the method?

I was looking into AutoFixture, and it looks like it might be able to handle something like this, but I can't quite wrap my head around the whole 'Freeze' vs 'Register' and it's integration with Moq.

like image 784
scottm Avatar asked Feb 23 '23 12:02

scottm


2 Answers

For Unittests you should only mock the direct dependencies. In your case you create PublicApi and inject a mock for ApiService and verify if PublicApi is calling the appropriate methods with the correct values on the ApiService Mock.

The same way you test all the other components isolated from the deeper dependencies.

If you want to test the combination of several components, that isn't unit testing but rather integration testing. Therefore it depends of how you are putting your classes together. e.g. if you are using an IoC container, it probably supports replacing the configuration for the repositories in some way. In this case you can use the configuration of the application and replace the repositories and potentially also the views with mocks.

like image 168
Remo Gloor Avatar answered Feb 25 '23 01:02

Remo Gloor


This may not be helpful in the least but I will say it anyway.

It seems you are trying to test too much at once, why not just test BillingService -> BillingValidation, then BillingService -> BillingRepository etc. This way you would have a suite of tests proving that each one works, then when you are up at the PublicApi Layer you only need to mock ApiService, as you have already tested everything beneath it, so there is no value in testing it again.

Generally I will only test 1 layer at a time, but I dont know your full scenario so you may have something which I am not accounting for, so if this is the case and you REALLY need to test all of this together I would just bring in a simple and lightweight DI framework like Ninject or something.

This way you can just bind all your types to mocks, then instanciate your PublicApi from it.

With ninject it would look something like:

Kernel.Bind<UserRepository>.ToConst(YourMockUserRepositoryInstance);
Kernel.Bind<UserService>.ToConst(YourMockUserServiceInstance);
Kernel.Bind<BillingRepository>.ToConst(YourMockBillingRepositoryInstance);
Kernel.Bind<BillingValidation>.ToConst(YourMockBillingValidationInstance);
Kernel.Bind<BillingService>.ToConst(YourMockBillingServiceInstance);
Kernel.Bind<AccountingFacade>.ToConst(YourMockAccountingFacadeInstance);
Kernel.Bind<ApiService>.ToConst(YourMockApiServiceInstance);
Kernel.Bind<PublicApi>.ToSelf();

var publicApi = Kernel.Get<PublicApi>();

Although you have to ask yourself, what are you testing here? if its just interactions I would do as I first mention, if its more then maybe think about the latter choice. Either way I hope it gives you some options.

like image 33
Grofit Avatar answered Feb 25 '23 01:02

Grofit