I am using Simple Injector for test purpose but pretty new on OOP. I am trying to create loosely couple classes. Here is the my scenario.
I have User repo and interface like this.
public class UserRepository : IUserRepository
{
public void Add(Model.User user)
{
Console.WriteLine("Name:"+user.Name+"\n"+"SurName:"+user.SurName);
}
public void Delete(int id)
{
throw new NotImplementedException();
}
}
public interface IUserRepository
{
void Add(User user);
void Delete(int id);
}
My TestInjectedClass Class and interface are something like this which I am planning to use in Program Main.
public class TestInjectedClass : ITestInjectedClass
{
private readonly IUserRepository _userRepository;
public TestInjectedClass(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void UserRepoRun()
{
var user = new User() {Id = 1,Name = "ada",SurName = "stack"};
_userRepository.Add(user);
}
}
public interface ITestInjectedClass
{
void UserRepoRun();
}
And My console program looks like this:
class Program
{
static ITestInjectedClass _testInjectedClass;
private static IUserRepository _userRepository;
static void Main(string[] args)
{
_testInjectedClass= new TestInjectedClass(_userRepository);
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
public Program()
{
Bootstrap.Start();
}
}
BootStrap class here:
class Bootstrap
{
public static void Start()
{
var container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
My problem when I run program, I am getting a value exception on the _userRepository inside TestInjectionClass.
How can I properly inject TestInjectionClass and UserRepository to Main Program. Thanks
You need to make Bootstrap.container available in Program.Main and then use it to create instances of classes instead of directly calling their constructors directly:
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
Of course you will need to expose it in Bootstrap for that to work:
class Bootstrap
{
public static Container container;
public static void Start()
{
container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
And call Bootstrap.Start from Program.Main:
static void Main(string[] args)
{
Bootstrap.Start();
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
The problem is because you are calling your Bootstrap code in Program class instance constructor.
So, actually when you start your program the execution environment, is calling entry point method Main. And your instance constructor is never executed.
Try changing your entry point method Main and 'Bootstrap' class code:
static void Main(string[] args)
{
var container = new Container();
Bootstrap.Start(container);
_testInjectedClass = container.GetInstance<TestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
class Bootstrap
{
public static void Start(Container container)
{
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
Please use SimpleInjector
Sample please refer
http://www.c-sharpcorner.com/UploadFile/4d9083/dependency-injection-using-simple-injector/
Related
I'm trying to make an unit test for a logger in an application.
For example I need to test the method Logger.info("some message"), but this method is static and return void.
Searching on Google I understand that I have to use Moq but am unable to implement that on the UnitTest class.
The Logger constructor does not have an argument and in x.Debug I have an error that says that I can't access
from instance reference.
Is there a way to implement UnitTest without editing the production code?
[TestClass()]
public class LoggerTests
{
[TestMethod()]
public void DebugTest()
{
var mock = new Mock<Logger>();
mock.Setup(x => x.Debug(It.IsAny<string>());
new Logger(mock.Object).AddLog("testing");
mock.VerifyAll;
}
}
Program.cs
private static void ConfigureLogger()
{
Logger.AddLog(new NLogAppender());
Logger.Level = TraceLevel.Verbose;
Logger.Info("Configured Logger");
}
Logger.cs
public class Logger
{
public static readonly List<IAppender> loggings = new List<IAppender>();
public static void AddLog(IAppender appender)
{
loggings.Add(appender);
}
public static TraceLevel Level { get; set; }
static Logger()
{
Level = TraceLevel.Verbose;
}
public static void Info(string message)
{
LogMessage(message);
}
}
NlogAppender.cs
public class NLogAppender : IAppender
{
public NLog.Logger logger;
public NLogAppender()
{
logger = LogManager.GetLogger(nameof(NLogAppender));
}
public void AddLog(string str)
{
}
}
IAppender.cs
public interface IAppender
{
void AddLog(string str);
}
You can't mock a static class, and you shouldn't mock the class/system under test.
Add a mock appender to the logger:
// Arrange
var logString = "test-info"
var appenderMock = new Mock<IAppender>();
appenderMock.Setup(a => a.AddLog(logString));
Logger.AddLog(appenderMock.Object);
// Act
Logger.Info(logString);
// Assert
// TODO: exactly once
appenderMock.VerifyAll();
Note this static class may persist data between tests causing unexpected results, consult your test framework for configuring this.
Apart from that, you usually don't want to roll your own logging infrastructure, there's lots of things you can do wrong and why reinvent the wheel? Plenty of ILogger(<T>) implementations around.
Is there any way to resolve the instance of a class at the controller level? I would like to override the previous instance created by unity and assign this new value via the controller.
Problem is I am not sure how to access the unity container in the web app controller.
Here is my code:
Repository:
public class UserRepository: IUserRepository
{
private UserInformation _userInfo;
public UserRepository(string headerValue)
{
_userInfo = LoadUserData(headerValue);
}
public UserInformation GetUserInfo()
{
return _userInfo;
}
}
public class UserInformation
{
public string FirstName;
public string LastName;
}
Unity Configuration:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//Some code omitted
config.DependencyResolver = new UnityDependencyResolver(UnityConfig.RegisterComponents());
}
}
public static class UnityConfig
{
public static UnityContainer RegisterComponents()
{
//Unity Configuration
var container = new UnityContainer();
container.RegisterType<IUserRepository, UserRepository>(new InjectionConstructor("DummyHeaderValue"));
return container;
}
}
Controller:
public class CustomerController : ApiController
{
public CustomerController()
{
//Something like this
container.Resolve<UserRepository>(new InjectionConstructor(Request.GetHeader("RealHeaderValueFromHttpRequest")));
}
}
Then I should be able to use the updated UserRepository instance throughout the application.
Any thoughts on how to achieve this?
Edit: As pointed out by #Nkosi I don't have access to Request in controller constructor. So let me rephrase my question again:
How would I initialise UserRepository with UserInformation object which contains details about the current user? The reason I want to do this is that throughout my application I want user details and I don't want to pass User Id from each method
Something like this: From any method throughout application
UserInformation obj = _userRepository().GetUserInfo();
Create an abstraction to get access to the request
public interface IHeaderService {
string RealHeaderValueFromHttpRequest();
}
Its Implementation will have access to the context and request to get the desired functionality
public class HeaderService : IHeaderService {
public string RealHeaderValueFromHttpRequest() {
return HttpContext.Current.Request.Headers["RealHeaderValueFromHttpRequest"];
}
}
The service will now be explicitly injected into the dependent repository
public class UserRepository: IUserRepository {
private readonly IHeaderService headerService;
public UserRepository(IHeaderService headerService) {
this.headerService = headerService;
}
public UserInformation GetUserInfo() {
var headerValue = headerService.RealHeaderValueFromHttpRequest();
var _userInfo = LoadUserData(headerValue);
return _userInfo;
}
//...
}
The repository will then also be explicitly injected into dependent controllers.
public class CustomerController : ApiController {
private readonly IUserRepository repositoty;
public CustomerController(IUserRepository repositoty) {
this.repository = repository;
}
public IHttpActionResult SomeAction() {
//NOTE: Only access user info in a controller action
var userInfo = repository.GetUserInfo();
//... use user info.
}
//...
}
Now all that is left is to make sure all abstractions and their implementations are registered with the dependency container
public static class UnityConfig {
public static UnityContainer RegisterComponents() {
//Unity Configuration
var container = new UnityContainer();
container.RegisterType<IUserRepository, UserRepository>();
container.RegisterType<IHeaderService, HeaderService>();
return container;
}
}
I have the next problem, i dont understand why this code dont work i think is because i dont injectate the class of constructor by autofac but i dont know how do that, can us help me to do that the better way?
Before I add the generator this work if i comment the generator code in service work.
This is my code:
I have a class Controller that invoke a serv:
public class ZonesController : Controller
{
private IZoneService zoneService;
public ZonesController(IZoneService zoneService)
{
this.zoneService = zoneService;
}
[HttpGet]
//Do work
}
This is the service and interface:
public class ZoneService : IZoneService
{
private readonly IZoneRepository zoneRepository;
private readonly IDtoFactory dtoFactory;
private readonly ZoneGenerator zoneGenerator;
public ZoneService(IZoneRepository zoneRepository,
IDtoFactory dtoFactory,
ZoneGenerator zoneGenerator)
{
this.zoneRepository = zoneRepository;
this.dtoFactory = dtoFactory;
this.zoneGenerator = zoneGenerator;
}
public void Add(ZoneDetailDTO zone)
{
zoneGenerator.Generate(zone);
}
//Do Work
}
public interface IZoneService
{
void Add(ZoneDetailDTO zone);
//Do Methods
}
The generator invoke ohter class, factories:
public class ZoneGenerator
{
private readonly ZoneFactory zoneFactory;
private readonly IZoneRepository zoneRepository;
public ZoneGenerator(ZoneFactory zoneFactory, IZoneRepository zoneRepository)
{
this.zoneFactory = zoneFactory;
this.zoneRepository = zoneRepository;
}
public void Generate(ZoneDetailDTO zoneModel)
{
var zone = zoneFactory.Create(zoneModel);
zoneRepository.Add(zone);
}
}
The Factory:
public class ZoneFactory
{
private readonly ZoneMapFactory zoneMapFactory;
private readonly ZoneScheduleFactory zoneScheduleFactory;
public ZoneFactory(ZoneMapFactory zoneMapFactory,
ZoneScheduleFactory zoneScheduleFactory)
{
this.zoneMapFactory = zoneMapFactory;
this.zoneScheduleFactory = zoneScheduleFactory;
}
public Zone Create(zoneDetailDTO zone)
{
var map = zoneMapFactory.Create(zone.Map.Address, zone.Map.Latitude, zone.Map.Longitude);
var schedule = zoneScheduleFactory.Create(zone.Schedule.StartHour, zone.Schedule.EndHour);
return new Zone(zone.Name,
zone.ProvinceId,
map,
schedule,
zone.Tags);
}
}
And finally my container:
//method in Startup class Asp.Net Core
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_ => Configuration);
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterModule<DefaultModule>();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return new AutofacServiceProvider(container);
}
public class DefaultModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ZoneService>().As<IZoneService>();
builder.RegisterType<ZoneRepository>().As<IZoneRepository>();
builder.RegisterType<ProvinceService>().As<IProvinceService>();
builder.RegisterType<ProvinceRepository>().As<IProvinceRepository>();
builder.RegisterType<DtoFactory>().As<IDtoFactory>();
}
}
You have missed to add to your Load method the following:
builder.RegisterType<ZoneGenerator>().AsSelf();
builder.RegisterType<ZoneFactory>().AsSelf();
builder.RegisterType<ZoneMapFactory>().AsSelf();
builder.RegisterType<ZoneScheduleFactory>().AsSelf();
I am writing integration tests for ServiceStack with in-memory database and I ran into this exception: "System.IO.InvalidDataException ServiceStackHost.Instance has already been set" while trying to run multiple test classes together, each having its own AppHostHttpListenerBase. However, if I ran the test classes one at a time, it ran and passed without problems. One reason for having multiple classes is because I want to test the AppHost with different services/dependencies registered and also to group my tests logically. Below is a general snippet of my tests. I would like to be able run all the test at one go.
public class TestClassOne : IDisposable
{
string _endPoint = "http://localhost:54321/";
AppHostHttpListenerBase _appHost;
IDbConnectionFactory _dbConn = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider);
public TestClassOne()
{
_appHost = new UnitTestAppHost(_dbConn, ...){};
_appHost.Init().Start(_endPoint);
}
[Fact]
public void Test()
{
...
using(var db = _dbConn.Open())
{
Assert.True(...);
}
}
public void Dispose()
{
_appHost.Dispose();
_appHost = null;
}
}
public class TestClassTwo : IDisposable
{
string _endPoint = "http://localhost:54321/";
AppHostHttpListenerBase _appHost;
IDbConnectionFactory _dbConn = new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider);
public TestClassTwo()
{
_appHost = new UnitTestAppHost(...){};
_appHost.Init().Start(_endPoint);
}
[Fact]
public void Test()
{
...
using(var db = _dbConn.Open())
{
Assert.True(...);
}
}
public void Dispose()
{
_appHost.Dispose();
_appHost = null;
}
}
I have tried running on another AppDomain, but it doesn't seems to be what I am looking for I think, because I need to do some Asserts on IDbConnection in the current running AppDomain (?), if that make any sense. Any suggestions on how I should be doing it? I'm using xUnit and Resharper's test runner btw.
I ended up fixing this by creating an AppHostSetupFixture class with a public static AppHost variable. Create a [SetUp] method that initializes your app host and a [TearDown] method that disposes it. Use AppHostSetupFixture.AppHost in your test classes.
[SetUpFixture]
public class AppHostSetupFixture
{
public static ServiceStackHost AppHost;
[SetUp]
public void Setup()
{
AppHost = new BasicAppHost(typeof(FeatureService).Assembly)
{
ConfigureContainer = container =>
{
var l = new List<string>();
l.Add(ConfigurationManager.ConnectionStrings["Redis"].ConnectionString);
container.Register<IRedisClientsManager>(c => new RedisManagerPool(l, new RedisPoolConfig() { MaxPoolSize = 40 }));
}
}
.Init();
}
[TearDown]
public void TearDown()
{
AppHost.Dispose();
}
}
This error is a result of trying to run multiple AppHosts per AppDomain. Each ServiceStack AppHost is a singleton and only allows a single AppHost per AppDomain.
If you did this:
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IService, DataService>();
container.RegisterType<IService, LoggingService>("Logging");
container.RegisterType<IService, CachingService>("Caching");
var services = container.ResolveAll<IService>();
foreach (var service in services)
Console.WriteLine(service);
Console.ReadKey();
}
}
interface IService { }
class DataService : IService { }
class LoggingService : IService { }
class CachingService : IService { }
The output you would get would include only the named mappings and would not include the default DataService mapping. The output of this program would be:
MoreUnityPractice.LoggingService
MoreUnityPractice.CachingService
Why did they decide not to get the default, unnamed mapping/registration with ResolveAll?
It was done this way so that you can have a Composite.
An example Composite IService
public class CompositeDataService : IService
{
public readonly IService[] services;
public CompositeDataService(IService[] services)
{
this.services = services;
}
}
And a demonstration test
[Fact]
public void Test()
{
var container = new UnityContainer();
container.RegisterType<IService, CompositeDataService>();
container.RegisterType<IService, LoggingService>("Logging");
container.RegisterType<IService, CachingService>("Caching");
var service = container.Resolve<IService>();
Assert.IsType<CompositeDataService>(service);
Assert.Equal(2, ((CompositeDataService)service).services.Count());
}
It is officially documented here
The two overloads of this method [ResolveAll] accept either an interface or a type name, and they return an instance of IEnumerable that contains references to all registered objects of that type that are not default mappings. The list returned by the ResolveAll method contains only named instance registrations. The ResolveAll method is useful if you have registered multiple object or interface types using the same type but different names
Here is some code to work around it (Note: I haven't run the code)
using System;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
public class Remember : UnityContainerExtension
{
protected override void Initialize()
{
this.Context.Registering += this.OnRegistering;
this.Context.RegisteringInstance += this.OnRegisteringInstance;
}
private void OnRegisteringInstance(object sender, RegisterInstanceEventArgs e)
{
if(string.IsNullOrEmpty(e.Name))
{
string uniqueName = Guid.NewGuid().ToString();
this.Context.RegisterNamedType(e.RegisteredType, uniqueName);
this.Context.Policies.Set<IBuildKeyMappingPolicy>(
new BuildKeyMappingPolicy(new NamedTypeBuildKey(e.RegisteredType)),
new NamedTypeBuildKey(e.RegisteredType, uniqueName));
}
}
private void OnRegistering(object sender, RegisterEventArgs e)
{
if (e.TypeFrom != null && string.IsNullOrEmpty(e.Name))
{
string uniqueName = Guid.NewGuid().ToString();
this.Context.RegisterNamedType(e.TypeFrom, uniqueName);
if (e.TypeFrom.IsGenericTypeDefinition && e.TypeTo.IsGenericTypeDefinition)
{
this.Context.Policies.Set<IBuildKeyMappingPolicy>(
new GenericTypeBuildKeyMappingPolicy(new NamedTypeBuildKey(e.TypeTo)),
new NamedTypeBuildKey(e.TypeFrom, uniqueName));
}
else
{
this.Context.Policies.Set<IBuildKeyMappingPolicy>(
new BuildKeyMappingPolicy(new NamedTypeBuildKey(e.TypeTo)),
new NamedTypeBuildKey(e.TypeFrom, uniqueName));
}
}
}
}
With an example
[TestMethod]
public void CanResolveMultipeDefaultMappingsUsingResolveAll()
{
var container = new UnityContainer().AddNewExtension<Remember>();
container.RegisterType<IFoo, One>();
container.RegisterType<IFoo, Two>();
container.RegisterType<IFoo, Three>();
IFoo[] foos = container.ResolveAll<IFoo>().OrderBy(f => f.GetType().Name).ToArray();
Assert.AreEqual(3, foos.Length);
Assert.IsInstanceOfType(foos[0], typeof(One));
Assert.IsInstanceOfType(foos[1], typeof(Three));
Assert.IsInstanceOfType(foos[2], typeof(Two));
}