I have a Autofac module as below
public class ServiceInjector:Module
{
protected override void Load(ContainerBuilder builder)
{
// many registrations and type looking up here
...
// One of the registration, say t which is found
// in above looking, is a resource consuming type
builder.RegisterType(t).As<ITimeConsume>();
// ...
}
}
And this module is used in a ServiceClass:
public class ServiceClass
{
static IContainer _ioc;
public ServiceClass()
{
var builder = new ContainerBuilder();
builder.RegisterModule<ServiceInjector>();
_ioc = builder.Build();
}
public void InvokeService()
{
using(var scope = _ioc.BeginLifetimeScope())
{
ITimeConsume obj = scope.Resolve<ITimeConsume>(...);
var result = obj.DoTimeConsumingJob(...);
// do something about result here ...
}
}
}
My questions is: how do I test ServiceClass by mocking (Moq) ITimeConsume class ? Here I try to write a test below:
public void Test()
{
Mock<ITimeConsume> moc = GetMockObj(...);
// How can I inject moc.Object into ServiceInjector module,
// so that ServiceClass can use this mock object ?
}
If this is not possible for the way, what's a better design for mocking the time consuming class which can also be injected?
**
Update:
**
Thanks #dubs and #OldFox hints. I think the key is that the Autofac injector should be initialized externally instead of internal controlled. So I leverage 'On Fly' building capability of Autofac.ILifetimeScope and design ServiceClass constructor with a LifeTime scope parameter. With this design I can on-flying registering any service in the unit test as below example:
using(var scope = Ioc.BeginLifetimeScope(
builder => builder.RegisterInstance(mockObject).As<ITimeConsume>())
In the current design you cannot inject your mock object.
The simplest solution with the least changes is to add an Internal Cto'r to ServiceClass:
internal ServiceClass(IContainer ioc)
{
_ioc = ioc;
}
Then use the attributte InternalsVisibleTo to enable the using of the C`tor in your test class.
In the arrange/setup/testInit phase initialize your class under test with the container which contains the mock object:
[SetUp]
public void TestInit()
{
Mock<ITimeConsume> moc = GetMockObj(...);
builder.RegisterInstance(moc).As<ITimeConsume>();
...
...
_target = new ServiceClass(builder.Build());
}
Personally I have multiple container instances. One for each endpoint.
Test project
public class AutofacLoader
{
public static void Configure()
{
var builder = new ContainerBuilder();
builder.RegisterModule<ServiceProject.ServiceInjector>();
builder.RegisterModule<LocalTestProject.AutofacModule>();
Container = builder.Build();
}
public static IContainer Container { get; set; }
}
The local test project autofac module is then free to override the service project module with specific registrations.
If more than one component exposes the same service, Autofac will use the last registered component as the default provider of that service: http://autofac.readthedocs.org/en/latest/register/registration.html#default-registrations
Test class
public void Test()
{
AutofacLoader.Configure();
var x = AutofacLoader.Container.Resolve<ITimeConsume>();
}
Related
I'm trying to register decorator for service these uses property injection.
When I'm adding containerBuilder.RegisterDecorator<ServiceDecorator, IService>() that properties are no longer injected.
I guess Autofac is trying to inject it to the decorator instead of original service.
I've written some tests to showcase this problem. There are services and the decorator:
public interface IService
{
bool NestedServiceIsNotNull();
}
public interface INestedService { }
public class Service : IService
{
public INestedService NestedService { get; set; }
public bool NestedServiceIsNotNull()
{
return NestedService != null;
}
}
public class NestedService : INestedService { }
public class ServiceDecorator : IService
{
private readonly IService _original;
public ServiceDecorator(IService original)
{
_original = original;
}
public bool NestedServiceIsNotNull()
{
return _original.NestedServiceIsNotNull();
}
}
And the test methods:
[TestMethod]
public void PropertyInjectedServiceShouldNotBeNull()
{
var builder = new ContainerBuilder();
builder.RegisterType<NestedService>().As<INestedService>();
builder.RegisterType<Service>().As<IService>().PropertiesAutowired();
var container = builder.Build();
var service = container.Resolve<IService>();
Assert.IsTrue(service.NestedServiceIsNotNull());
}
[TestMethod]
public void PropertyInjectedServiceShouldNotBeNullEvenIfDecoratorRegistered()
{
var builder = new ContainerBuilder();
builder.RegisterType<NestedService>().As<INestedService>();
builder.RegisterType<Service>().As<IService>().PropertiesAutowired();
// Here's the difference - decorating the service
// causes the assertion to fail.
builder.RegisterDecorator<ServiceDecorator, IService>();
var container = builder.Build();
var service = container.Resolve<IService>();
Assert.IsTrue(service.NestedServiceIsNotNull());
}
The first test passes but the second fails by assertion.
Is it correct behavior?
I'm working with a legacy project, so I shouldn't to change existing code by moving dependencies to the constructor.
Is there any way to solve this problem?
It appears... you've found a bug! Yow! I've filed an issue on your behalf here.
All is not lost, however - you can still use decorators the way you want, you'll just have to use the older less-pretty Autofac decorator syntax to get it done.
var builder = new ContainerBuilder();
builder.RegisterType<NestedService>().As<INestedService>();
// Decorating the service with the old syntax works.
builder.RegisterType<Service>().Named<IService>("service").PropertiesAutowired();
builder.RegisterDecorator<IService>((c, inner) => new ServiceDecorator(inner), fromKey: "service");
var container = builder.Build();
var service = container.Resolve<IService>();
Assert.True(service.NestedServiceIsNotNull());
There is more documentation on how to work with this older syntax here.
I write integration tests for my application, and use my container for this. I want to be able to register all the components as I do in real running, and then override some of the components and switch them to use stubs implementations.
I wouldn't want to seperate the DI and have a container for tests only because I want to test the real thing.
Doing this also seems ugly:
public class MyRegistrations
{
public static RegisterAll(bool isInTest= false)
{
if (isTest)
{
// Register test fakes
}
else
// Register real components
}
}
So I thought of overriding registrations in my test enviorment. How should it be done?
Any other better ways for achieving my goal?
Thanks
Autofac will use the last registered component as the default provider
of that service
From the AutoFac documation.
In your arrange/setup/testInit phase register the mocks, then resolve the SUT:
[SetUp]
public void TestInit()
{
Mock<IFoo> mock = new Mock<IFoo>();
builder.RegisterInstance(mock.object).As<IFoo>();
...
...
_target = builder.Resolve<The component>();
}
Note:
Singletons, static members and SingletonLifestyle(registration) may cause some troubles....
Well, for example you can create a static action method inside your composition root to alter the current configuration and call it during testing. For example:
public class CompositionRoot
{
public static Action<IContainer> OverrideContainer = c => { };
internal static IContainer CreateContainer()
{
ContainerBuilder builder = new ContainerBuilder();
/// etc. etc.
var container = builder.Build();
OverrideContainer(container);
return container;
}
}
After that you can create a mock of you server, for example, like this:
[TestFixture]
public class ConfigurationControllerFixture : BaseServer
{
[Test]
public async Task verify_should_get_data()
{
var response = await GetAsync(Uri);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
protected override string Uri
{
get { return "api/configuration"; }
}
}
public abstract class BaseServer
{
protected TestServer Server;
protected abstract string Uri { get; }
protected virtual void OverrideConfiguration()
{
CompositionRoot.OverrideContainer = c =>
{
// new autofac configuration
cb.Update(c);
};
AppStartup.OverrideConfiguration = c =>
{
// same as explained, but for HttpConfiguration
};
}
}
[SetUp]
public void Setup()
{
OverrideConfiguration();
Server = Microsoft.Owin.Testing.TestServer.Create(app =>
{
var startup = new AppStartup();
startup.Configuration(app);
});
PostSetup(Server);
}
Hope it helps :)
If you want to write integration test from API to database you can use XUnit. XUnit use TestHost and WebApplicationFactory to create a System under test. With XUnit, it's very easy to mock a test service by add test service to service collection.
I made a open source project use XUnit to test my API work with mySQL database. Please visit here for example https://gitlab.com/quorion-group/quorion-backend-crm
I am trying to use named registration in the program. But example from documentation does not work.
http://autofac.readthedocs.org/en/latest/advanced/keyed-services.html#named-services
public class DbLoggerModule : Autofac.Module
{
protected override void Load(Autofac.ContainerBuilder builder)
{
builder.Register<DbLogger>().Named<ILogger>("1");
}
and got compilation error: No overload for method 'Register' takes 0 arguments
I also tried the following variants:
builder.RegisterType<DbLogger>().Named<ILogger>("1");
builder.RegisterType<DbLogger>().Named<ILogger>("1").As<ILogger>();
builder.RegisterType<DbLogger>().Named<ILogger>("1").As<ILogger>();
builder.RegisterType<DbLogger>().As<ILogger>().Named<ILogger>("1");
They do not cause a compile error.
But as it is not impossible to obtain a given named service:
var lll = _сontainer.ResolveNamed< ILogger >("1");
throws an exception:
The requested service '1 (Console1.ILogger)' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
IEnumerable loggers =
_сontainer.Resolve< IEnumerable< ILogger > >();
Returns an empty list
UPDATE
Part of the problem was solved. During the experiments, I have created a few interfaces with similar names. As a result, I register one interface, but resolved other.
Now this line is working:
var lll = _сontainer.ResolveNamed< ILogger >("1");
However, I can not get a complete list of classes that implement the interface:
var lll = _сontainer.ResolveNamed<ILogger>("1");
lll.Log(null); // working !
IEnumerable< ILogger >loggers=_сontainer.Resolve<IEnumerable< ILogger >>();// It returns an empty list
ALSO
When I refuse to named services, the programm begins to work:
builder.RegisterType<DbLogger>().As<ILogger>();
...
_сontainer.Resolve<IEnumerable<ILogger>>(); // working !
I suspect that we can not get a list of services registered as named.
Someone can confirm this?
UPDATE 2
Here is a very simple but complete example. It does not work. Why ?
public interface ISimpleService
{
string Test();
}
public class SimpleService1 : ISimpleService
{
public string Test()
{
return "Hello World from SimpleService1";
}
}
internal class Program
{
private static void Main(string[] args)
{
var builder = new ContainerBuilder();
{
builder.RegisterType<SimpleService1>().Named<ISimpleService>("fff");
}
IContainer container = builder.Build();
var services = container.Resolve<IEnumerable<ISimpleService>>();
Console.WriteLine(services.Count()); // 0. Why ?
}
}
You are trying to resolve ISimpleService (interface), but SimpleService1 registered only as class (because the named registration), not as interface.
Try this:
builder.RegisterType<SimpleService1>().Named<ISimpleService>("fff").As<ISimpleService>();
or
builder.RegisterType<SimpleService1>().Named<ISimpleService>("fff").AsImplementedInterfaces();
A fully working example:
public interface ISimpleService
{
string Test();
}
public class SimpleService1 : ISimpleService
{
public string Test()
{
return "Hello World from SimpleService1";
}
}
internal class Program
{
private static void Main(string[] args)
{
var builder = new ContainerBuilder();
{
builder.RegisterType<SimpleService1>().Named<ISimpleService>("fff").As<ISimpleService>();
}
IContainer container = builder.Build();
var services = container.Resolve<IEnumerable<ISimpleService>>();
Console.WriteLine(services.Count()); // 1.
}
}
Initial sample will work if resolve ISimpleService by name:
var services = container.ResolveNamed<IEnumerable<ISimpleService>>("fff");
If you want to resolve a list of named (and only those, no the ones registered with a name and without, as suggested in other answers), here is what you can do:
builder.RegisterType<Foo>().Named<IFoo>("IFoo").SingleInstance();
builder.RegisterType<Foo2>().Named<IFoo>("IFoo").SingleInstance();
builder.RegisterType<Foo3>().Named<IFoo>("2").As<IFoo>().SingleInstance();
var container = builder.Build();
//Will resolve type Foo2
var foo = container.ResolveNamed<IFoo>("IFoo");
//Will resolve 2 IFoo: Foo and Foo2
var foos = container.ResolveNamed<IEnumerable<IFoo>>("IFoo");
Your code should work.
Are you sure you have registered your module in your container?
Ensure something like this when bootstrapping your container (assembly scanning or plain registration):
// This example being fx a console app
containerBuilder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());
// Basic registration
containerBuilder.RegisterModule<LoggerModule>();
// Ensure the container is build
_container = containerBuilder.Build();
I need to execute some one-time code on start of my application in the global.asax. I've already got autofac up and running with numerous registrations but the problem is that I can't figure out how to resolve or inject a dependency into SecurityConfig.RegisterActivities() that's inside my global.asax.
I tried manually resolving the dependency myself in global.asax using the autofac container but it threw the exception "No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested."
How do I get this dependency into that class?
protected void Application_Start()
{
var builder = new ContainerBuilder();
DependencyRegistrar dr = new DependencyRegistrar();
dr.Register(builder);
new SecurityConfig().RegisterActivities(); // this needs injecting into or resolving of IServiceManager instance
}
public class DependencyRegistrar
{
public virtual IContainer Register(ContainerBuilder builder)
{
builder.RegisterType<ServiceManager>().As<IServiceManager>().InstancePerHttpRequest();
builder.RegisterType<SecurityConfig>().AsSelf().PropertiesAutowired().InstancePerDependency();
}
}
public class SecurityConfig
{
public void RegisterActivities()
{
ServiceManager.DoSomething();
}
public IServiceManager ServiceManager { get; set; }
}
This allowed me to resolve my dependencies finally.
using(var scope = container.BeginLifetimeScope("AutofacWebRequest"))
{
scope.Resolve<SecurityConfig>().RegisterActivities();
}
I'm struggling with how to organize my Autofac component registrations in modules given that some of the modules themselves have dependencies.
I've implemented an abstraction of configuration data (i.e. web.config) in an interface:
interface IConfigurationProvider
{
T GetSection<T>(string sectionName)
where T : System.Configuration.ConfigurationSection;
}
along with implementations for ASP.NET (WebConfigurationProvider) and "desktop" applications (ExeConfigurationProvider).
Some of my autofac modules then require an IConfigurationProvider as a constructor parameter, but some don't:
class DependentModule : Module
{
public DependentModule(IConfigurationProvider config)
{
_config = config;
}
protected override void Load(ContainerBuilder builder)
{
var configSection = _config.GetSection<CustomConfigSection>("customSection");
builder.RegisterType(configSection.TypeFromConfig);
}
private readonly IConfigurationProvider _config;
}
class IndependentModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(/* other stuff not based on configuration */);
}
}
Since the RegisterType() extension method doesn't accept a registration delegate (Func<IComponentContext, T>), like Register() does, I can't register the IConfigurationProvider up-front and then resolve it when I go to register the type specified in the configuration, something like:
// this would be nice...
builder.RegisterType(c => c.Resolve<IConfigurationProvider>().GetSection<CustomConfigSection>("sectionName").TypeFromConfig);
This means that I need to be able to register modules with and without a dependency on IConfigurationProvider.
It's obvious how to manually instantiate each module and register it:
IConfigurationProvider configProvider = ...;
var builder = new ContainerBuilder();
builder.RegisterModule(new DependentModule(configProvider));
builder.RegisterModule(new IndependentModule());
using (var container = builder.Build())
{
...
}
But I don't want to manually instantiate my modules - I want to scan assemblies for modules and register them automatically (as discussed in this question). So I have to use reflection to scan the assembly for IModule types, and use Activator.CreateInstance to make registerable instances. But how do I know whether or not to pass an IConfigurationProvider as a constructor parameter. And what happens when other modules have additional or different dependencies?
There's got to be a more straightforward way of accomplishing the basic task: register a type specified in some configuration provided via an interface, right? So how do I do that?
You could do something like this:
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Autofac.Core;
using NUnit.Framework;
namespace Yo_dawg
{
[TestFixture]
public class I_heard_you_like_containers
{
[Test]
public void So_we_built_a_container_to_build_your_container()
{
var modules = GetModules();
Assert.That(modules.Length, Is.EqualTo(4));
var builder = new ContainerBuilder();
foreach (var module in modules)
builder.RegisterModule(module);
var container = builder.Build();
}
private IModule[] GetModules()
{
var builder = new ContainerBuilder();
var configurationProvider = new ConfigurationProvider();
builder.RegisterInstance(configurationProvider).AsImplementedInterfaces().ExternallyOwned();
builder.RegisterAssemblyTypes(GetType().Assembly)
.Where(t => t.IsAssignableTo<IModule>())
.AsImplementedInterfaces();
using (var container = builder.Build())
return container.Resolve<IEnumerable<IModule>>().ToArray();
}
}
public class ModuleA : Module
{
public ModuleA(IConfigurationProvider config)
{
}
}
public class ModuleB : Module
{
public ModuleB(IConfigurationProvider config)
{
}
}
public class ModuleC : Module
{
}
public class ModuleD : Module
{
}
public interface IConfigurationProvider
{
}
public class ConfigurationProvider : IConfigurationProvider
{
}
}
For this scenario, Autofac's own XML configuration seems to cover the scenarios you're targeting. Adding a new IConfigurationProvider mechanism seems like reinventing this functionality already provided by the container. The basics are documented at: https://code.google.com/p/autofac/wiki/XmlConfiguration. The configuration syntax has in-built support for modules.
There's a nice alternative by Paul Stovell that allows modules to be registered in code yet receive parameters from config - see: http://www.paulstovell.com/convention-configuration. Hope this helps!