Simple Injector, can't override existing registration - c#

I am currently using Simple Injector for the first time. In my .NET project I am running test and mocking data returned from a web service and registering the object to the container like so
_container.Register<IWebServiceOrder>(() => mock.Object, Lifestyle.Transient);
This works fine. But in my tests I want to test the behavior of the system on a second call to the web service that will contain updated data, so the mock object will need to be updated.
By default Simple Injector does not allow Overriding existing registrations but the official website states it is possible to change this behavior like below.
https://simpleinjector.readthedocs.org/en/latest/howto.html#override-existing-registrations
container.Options.AllowOverridingRegistrations = true;
Unfortunately i still get an error when i try to register the object a second time even with the above code.
The container can't be changed after the first call to GetInstance, GetAllInstances and Verify
Any ideas on why this is happening?

Replacing an existing registration after you already worked with the container hardly ever has the behavior you would expect (and this holds for all DI libraries) and that's the reason why the Simple Injector container is locked. This is described in more details here (as #qujck already pointed out).
First of all, if you are writing unit tests, you shouldn't use a container at all. Your unit tests should create the class under test themselves, or you extract this logic to a convenient factory method, such as:
private static MailNotifier CreateMailNotifier(
IDeposit deposit = null, ISendMail mailSender = null, ILog logger = null)
{
return new MailNotifier(
deposit ?? Substitute.For<IDeposit>(),
mailSender ?? Substitute.For<ISendMail>(),
logger ?? Substitute.For<ILog>());
}
This factory method is a variation to the Test Data Builder pattern.
By making use of optional parameters, it allows the unit test to specify only the fake implementation it requires during testing:
public void Notify_WithValidUser_LogsAMessage()
{
// Arrange
var user = new User();
var logger = new FakeLogger();
MailNotifier sut = CreateMailNotifier(logger: logger);
// Act
sut.Notify(user);
// Assert
Assert.AreEqual(expected: 1, actual: logger.LoggedMessages.Count);
}
If you use a container, because creating the class under test by hand is too cumbersome, it indicates a problem in your class under test (most likely a Single Responsibility Principle violation). Prevent using tools to work around problems in your design; your code is speaking to you.
For integration tests however, it is much more usual to use the container, but in that case you should simply create a new container for each integration test. This way you can add or replace the IWebServiceOrder without any problem.

Related

Why ninject gets different Db instances in nunit?

I write integration tests for ASP.NET MVC based application, and I try to resolve ninject registration issue.
So for my ASP.NET MVC registration I have
kernel.Bind(typeof(ICustomDbContext), typeof(IUnitOfWork))
.ToMethod(ctx => ctx.Kernel.Get<CustomDbContext>())
.InRequestScope();
Just to clarify CustomDbContext implements IUnitOfWork and ICustomDbContext.
With that registration i guarantee that i have one unique instance per request for CustomDbContext. That registration works properly in scope of ASP.NET.
The problem is when i write integration tests.
[SetUp]
public void SetUp()
{
kernel = NinjectConfig.CreateKernel();
}
[Test]
public async Task Test()
{
// Arrange
var claaService = kernel.Get<IService>();
}
On set up step i load my composition root (which is in ASP.NET MVC project).
The problem is when i get IService (Implementation of IService.cs is Service.cs and that service has dependencies to IUnitOfWork.cs and IGenericRepository.cs. IGenericRepository.cs has dependency to ICustomDbContext).
At the end when i access IService i should have same instance of CustomDbContext (and as I said in works in scope of MVC).
I have tried to resolve it in child scope, but the result is the same (they still have different hash code):
using (var childKernel1 = new ChildKernel(kernel))
{
childKernel1.Rebind(typeof(ICustomDbContext), typeof(IUnitOfWork))
.ToMethod(ctx => ctx.Kernel.Get<CustomDbContext>())
.InThreadScope();
var claaService = childKernel1.Get<IClassService>();
}
My questions are:
Why this is happening ?
How can I resolve it (it works if i do not use ninject, but i want to find a way with Ninject, even if i have to add additional configuration in integration tests) ?
Why this is happening ?
Ninject's scoping is limited to the lifetime of the container. You have setup the container to be created for each [Test] because you are using [SetUp].
This attribute is used inside a TestFixture to provide a common set of functions that are performed just before each test method is called.
[SetUp]
public void SetUp()
{
kernel = NinjectConfig.CreateKernel();
}
If you want to use the same container across multiple tests in the same [TestFixture] (assuming this because you said "instance is not the same", but you didn't mention same as what), you need to use [OneTimeSetup] instead.
This attribute is to identify methods that are called once prior to executing any of the tests in a fixture.
[OneTimeSetUp]
public void OneTimeSetUp()
{
kernel = NinjectConfig.CreateKernel();
}
This of course assumes all of your relevant integration tests are in a single class.
In short, your Ninject container is being re-initialized on every test, which means all instances it manages are also being re-initialized.

Mocking Library Method

I recently started tdd, but my mocking knowledge is incomplete. I know the basics but, Tests for some methods which were written without thinking tdd, really confuse me.
Here is what I am trying to test
public int GetThirdPartyUserId(int serviceTypeId, string accessToken)
{
ThirdPartyRequestDetail requestDetail = GetThirdPartyRequestDetails(serviceType, accessToken);
IHttwrapConfiguration configuration = new HttwrapConfiguration(requestDetail.BaseUrl);
IHttwrapClient httwrap = new HttwrapClient(configuration);
Task<IHttwrapResponse<OpenAuthUserResponse>> response = httwrap.GetAsync<OpenAuthUserResponse>(requestDetail.PathAndQuery);
try
{
if (response.Result.Data != null && response.Status != TaskStatus.Faulted)
{
//Do something
}
else
{
//WANT TO TEST HERE
}
}
}
Here is my test method
private Mock<IHttwrapClient> _httpwrap;
public void httprwapTest()
{
string accessToken = "invalid";
int thirdPartySiteId = (int)ThirdPartyServiceType.GooglePlus;
string requestPath = _fixture.Create<string>();
_httpwrap.Setup(item => item.GetAsync(requestPath)).Returns(Task.FromResult(new HttwrapResponse(HttpStatusCode.BadRequest, "body")));
OpenAuthUserResponse response = _oauthAuthenticator.GetThirdPartyUser(thirdPartySiteId, accessToken);
Assert.AreEqual(response.Error, OauthAuthenticatorErrorType.RequestFaulted);
}
What I tried to do is below but it didn't get triggered.
_httpwrap.Setup(item => item.GetAsync(requestPath)).Returns(Task.FromResult(new HttwrapResponse(HttpStatusCode.BadRequest, "body")));
How I can test my classes behaviour when httpwrap gives me a badrequest response code?
In it's current form, you can't use a conventional mocking framework to help with your test. In order for the Mocking to work, you have to Setup the same mock that you're using in your production code. Currently there's no connection between the mock you're creating in your test and the IHttpwrapClient that your method under test depends on.
The first step you would need to do take is to move the creation of the HttpwrapClient outside of the method that you want to test. You then need to make it available to the code, via it's interface, in a way that you can later supply it from your test.
There are three common ways of supplying the interface.
Inject it into the constructor for your class
Inject it through a property on your class
Pass it as an argument to the function
Generally constructor injection is preferred over property injection, but it's largely up to you which approach is going to work best (they each have positives and negatives) and what makes most sense for the data that you're injecting.
You would then create the Mock of your interface and inject it into your code as appropriate.
As far as your production code goes, you're still going to need to create an instance of your concrete class. You can either do this directly when calling your class, or via something like a factory, or by using an IoC container, like Castle Winsor or Ninject (there are several others).

Unit Testing Methods that make WCF Service Call?

First attempt at any real unit testing. I have a WPF client application which receives data from methods in a WCF service. These method calls are made directly from my view models in the client app:
public string LoadArticle()
{
MyServiceClient msc = new MyServiceClient();
return Article = msc.GetArticle(_UserName);
}
I then have a test project where I new up a viewmodel then call my method:
[TestMethod]
public void LoadArticleTestValid()
{
var articleViewModel = new ArticleViewModel("Thomas");
string userName = "Thomas";
string expected = "Article 1";
var actual = articleViewModel.LoadArticle(userName);
etc.
}
Obviously this test will fail because the client application cannot reach the service to invoke LoadArticle. How is this situation tackled? Do I use Dependency Injection and pass a IMyService interface of some kind into the constructor instead of creating MyServiceClient in the ViewModel or do I mock the service somehow?
This is the problem:
MyServiceClient msc = new MyServiceClient();
This creates a tight coupling between ArticleViewModel and MyServiceClient. In order to unit test just ArticleViewModel this dependency would need to be mocked. If there's an IMyServiceClient then you'd supply that to the class:
public ArticleViewModel
{
private IMyServiceClient ServiceClient { get; set; }
public ArticleViewModel(IMyServiceClient serviceClient)
{
this.ServiceClient = serviceClient;
}
// etc.
}
Then code within that class wouldn't create a new service client, it would just use the one that's in that property.
Then in the unit test you'd create a mock of IMyServiceClient, define expected behaviors on that mock, and supply it to the object being tested. How you do that depends on the mocking library. A quick example in Rhino Mocks might look like this:
// arrange
var serviceClient = MockRepository.GenerateMock<IMyServiceClient>();
serviceClient.Stub(c => c.GetArticle(Arg<string>.Is.Anything)).Return("Article 1");
var model = new ArticleViewModel(serviceClient);
// act
var result = model.LoadArticle("Thomas");
// assert
Assert.AreEqual("Article 1", result);
The idea here is that the unit test is only testing the LoadArticle method, not the dependencies invoked by that method. Those dependencies are supplied with expected behaviors and the result is examined based on those expected behaviors.
Note: There's nothing stopping the unit test from supplying the actual implementation of MyServiceClient as well, instead of a mock. The unit test project just needs the configuration for that service to work. (Unit test projects are application hosts, they can have App.config files.) This would be an integration test rather than a unit test, but the same assertions of the results can be made.
Yes, I think you are right I would suggest a constructor parameter of IMyService, which you can use to inject a mock into the object for testing.
Further! I would suggest not using the autogenerated service client. if you copy and paste the code out into your own class you can make it implement IMyService and effectivly hide the fact that it uses WCF, goes direct to the DB or is a mocked object from the real code.
this will allow you to inject your Mock into the WPF for UI testing

Simple Injector FilterInjection seems to be reinitialising RegisterPerWebRequest injected item

I'm trying to move from Ninject to Simple Injector but I'm experiencing an odd issue when trying to duplicate functionality that worked with Ninject.
In Ninject I had a service which contained:
private readonly ICollection<Message> messages;
This service was registered as
Bind<INotificationService>().To<NotificationService>()
.InRequestScope();
This service allowed messages (UI and error) to be passed back to the MVC site.
This service was injected into an ActionFilterAttribute:
kernel.BindFilter<CriticalErrorAttribute>(FilterScope.Last, 1)
.When((context, ad) =>
!string.IsNullOrEmpty(ad.ActionName) &&
ad.ControllerDescriptor.ControllerName.ToLower() != "navigation");
and used within OnActionExecuted.
Because the service was registered to Ninject with InRequestScope, any items pushed to the message queue were available in the Actionfiter. This allowed for a redirect to an error page (displaying critical errors) if necessary.
I've tried to duplicate this with simpleinjector:
container.RegisterPerWebRequest<INotificationService, NotificationService>();
container.RegisterInitializer<CriticalErrorAttribute>(handler =>
{
handler.NotificationService =
container.GetInstance<INotificationService>();
});
The injection is working fine, but even though the message collection contains messages prior to entering the ActionFilter, once in the filter the message collection is empty. It's like the RegisterPerWebRequest is being ignored.
Any help in solving this issues would be appreciated.
UPDATE:
In Simple Injector 2.5 a new RegisterMvcIntegratedFilterProvider extension method has been added to the MVC Integration package that replaces the old RegisterMvcAttributeFilterProvider. This new RegisterMvcIntegratedFilterProvider contains the behavior of the SimpleInjectorFilterAttributeFilterProvider that is given below and allows better integration of attributes into the Simple Injector pipeline. This does mean however that by default, no properties are injected, but this can extended by implementing a custom IPropertySelectionBehavior. The use of the new RegisterMvcIntegratedFilterProvider is adviced over the old RegisterMvcAttributeFilterProvider method, which will be marked [Obsolete] in a future release.
When using the RegisterMvcAttributeFilterProvider extension method, Simple Injector will not call any registered initializer on MVC attributes. If you set a break point inside the anonymous delegate that injects the NotificationService you'll see it's never hit.
Simple Injector does however call the container.InjectProperties method on MVC attributes, but InjectProperties does implicit property injection, which means that it tries to inject all public properties on a type, but skips it if the property can't be injected (for what ever reason).
I bet the CriticalErrorAttribute.NotificationService property has a type of NotificationService instead of INotificationService. Since you didn't register NotificationService explicitly, the container will create a transient instance for you, which means you'll get a different instance for the CriticalErrorAttribute than the rest of the application is getting.
Quick fix: change the property type to INotificationService.
To be honest, I regret ever implemented the MVC integration package for Simple Injector to use the InjectProperties method. Implicit Property injection is very evil, because it doesn't fail fast when there's a misconfiguration and I'm even thinking about removing support for InjectProperties in the future. The problem is however that many developers are depending on InjectProperties. Either directly by calling it, or indirectly by letting the container inject properties on MVC attributes.
InjectProperties does not run any initializer. That's by design, and there are other constructs that allow running the full initialization process on objects that are not created by the container. Problem is however, that adding this could break existing clients, since this could result in properties being injected multiple times.
In your case, I suggest a different solution:
Prevent calling container.RegisterMvcAttributeFilterProvider() in the startup path of your application. This will register a special FilterAttributeFilterProvider that calls InjectProperties internally. You don't want to use implicit property injection, you want a more explicit (and complete) behavior. Instead register the following class:
internal sealed class SimpleInjectorFilterAttributeFilterProvider
: FilterAttributeFilterProvider
{
private readonly ConcurrentDictionary<Type, Registration> registrations =
new ConcurrentDictionary<Type, Registration>();
private readonly Func<Type, Registration> registrationFactory;
public SimpleInjectorFilterAttributeFilterProvider(Container container)
: base(false)
{
this.registrationFactory = type =>
Lifestyle.Transient.CreateRegistration(type, container);
}
public override IEnumerable<Filter> GetFilters(
ControllerContext context,
ActionDescriptor descriptor)
{
var filters = base.GetFilters(context, descriptor).ToArray();
foreach (var filter in filters)
{
object instance = filter.Instance;
var registration = registrations.GetOrAdd(
instance.GetType(), this.registrationFactory);
registration.InitializeInstance(instance);
}
return filters;
}
}
You can use the following code to register this custom provider:
var filterProvider =
new SimpleInjectorFilterAttributeFilterProvider(container);
container.RegisterSingle<IFilterProvider>(filterProvider);
var providers = FilterProviders.Providers
.OfType<FilterAttributeFilterProvider>().ToList();
providers.ForEach(provider => FilterProviders.Providers.Remove(provider));
FilterProviders.Providers.Add(filterProvider);
This custom SimpleInjectorFilterAttributeFilterProvider calls the Registration.InitializeInstance method. This method allows initialization a type that is already created and will initialize it by (among other things) calling the type initializer delegates.
For more information about working with attributes, please read the following discussion.

Moq NHiberNate ISession.Get doesn't call mock session object

I am new to NHibernate and even newer to MOQ (or other similar frameworks). After searching online day and night (google + stackoverflow + others), I am turning here for help.
The scenario is (should be) simple. I am trying to unit test a call on a C# WCF service that uses NHibernate as the ORM layer. The method, after doing some initial work, finds a database to connect to, and then calls on the SessionProvider (a manager of session factories) to return a nhibernate session for a sharded DB. I am then trying to use ISession.Get<>() to retrieve an object from the database aand then do some work. The problem is that the GUID (the key for the entry that I am looking up in the db) is generated at the begining of the call and I have no way of knowing what it might be beforehand outside the scope of the WCF call. Hence, I cannot use sqllite or other techniques to pre-populate the necessary data to control the test. What I was hoping for was that I can somehow mock (inject a fake layer to?) the call to Session.Get to return an invalid object which should cause the WCF call to throw.
Here's the test code snippet:
var testRequest = ... (request DTO)
var dummyBadObject = ... (entity in DB)
var mock = new Mock<ISession>(MockBehavior.Strict);
mock.Setup(m => m.Get<SampleObject>(It.IsAny<Guid>())).Returns(dummyBadObject);
var exception = Assert.Throws<FaultException>(() => applicationService.SomeMethod(testRequest));
Assert.AreEqual(exception.Code.ToString(), SystemErrorFault.Code.ToString());
When I run this test, instead of interacting with the mock ISession object, the app service code calls the Get on the actual ISession object from the session factory, connects to the database and gets the right object. Seems like I am missing something very basic about mocks or injection. Any help will be appreciated.
Thanks,
Shawn
Based on our comments, the problem is that mocks are completely different from how you thought of them.
They don't magically intercept creations of classes derived from an interface. They are just dynamic implementations of it.
Creating a Mock<ISession> is not much different from creating a class that implements ISession. You still have to inject it in the services that depend on it.
You'll probably have to review your whole stack, as the capability to do this depends on a good decoupled design.
Suggested read: Inversion of control
I re-designed the components in my application to have a ServiceContext object which in turns holds all the other (what used to be static) components that the application uses. In this case, this would be the session provider (or the ISessionFactory cache), and similarly a WCF channel factory cache. The difference is that the ServiceContext provides methods to override the default instances of the different components allowing me to replace them with mock ones for testing and restoring the original ones when testing is done. This has allowed me to create a test where I mock all the way from the session cache to the ISession.Get/Save/Load etc.
var mockDatabaseSessionFactory = new Mock<DatabaseSessionManager>(MockBehavior.Strict);
var mockSession = new Mock<ISession>(MockBehavior.Strict);
var mockTransaction = new Mock<ITransaction>(MockBehavior.Strict);
mockDatabaseSessionFactory.Setup(x => x.GetIndividualMapDbSession()).Returns(mockSession.Object);
mockDatabaseSessionFactory.Setup(x => x.GetIndividualDbSession(It.IsAny<UInt32>())).Returns(mockSession.Object);
mockDatabaseSessionFactory.Setup(x => x.Dispose());
mockSession.Setup(x => x.BeginTransaction()).Returns(mockTransaction.Object);
mockSession.Setup(x => x.Dispose());
mockTransaction.Setup(x => x.Commit());
mockTransaction.Setup(x => x.Dispose());
// Setups to allow for the map insertion/deletion to pass
mockSession.Setup(x => x.Get<IndividualMap>(It.IsAny<string>())).Returns((IndividualMap)null);
mockSession.Setup(x => x.Load<IndividualMap>(It.IsAny<string>())).Returns((IndividualMap)null);
mockSession.Setup(x => x.Save(It.IsAny<IndividualMap>())).Returns(new object());
mockSession.Setup(x => x.Delete(It.IsAny<IndividualMap>()));
// Our test condition for this test: throw on attempt to save individual
mockSession.Setup(x => x.Save(It.IsAny<Individual>()))
.Throws(new FaultException(ForcedTestFault.Reason, ForcedTestFault.Code));
// Test it - but be sure to back up the previous database session factory
var originalDbSessionFactory = ServiceContext.DatabaseSessionManager;
ServiceContext.OverrideDatabaseSessionManager(mockDatabaseSessionFactory.Object);
try
{
var exception = Assert.Throws<FaultException>(() => applicationService.AddIndividual(addIndividualRequest));
Assert.IsTrue(ForcedTestFault.Code.Name.Equals(exception.Code.Name));
}
catch (Exception)
{
// Restore the original database session factory before rethrowing
ServiceContext.OverrideDatabaseSessionManager(originalDbSessionFactory);
throw;
}
ServiceContext.OverrideDatabaseSessionManager(originalDbSessionFactory);
ServiceContext.CommunicationManager.CloseChannel(applicationService);
Luckily the code design wasn't too bad o_O :) so i re-factored this bit easily and now code coverage is at 100! Thanks Diego for nudging me in the right direction.

Categories

Resources