I cant find any examples of using scopeRootBinder. I'm not sure if it can help me. Here's the problem(test). I need that each instance of ChildService gets build with its own instance of Component2.
[TestMethod]
public void CastleContainer_ChildServices_GetItsOwnObject()
{
var container = new WindsorContainer();
container.Register(Component.For<IRootService>().ImplementedBy<RootService>().LifestyleTransient()
.DependsOn(ServiceOverride.ForKey("childServices")
.Eq("ChildService", "ChildService")));
container.Register(Component.For<IChildService>().ImplementedBy<ChildService>().LifestyleTransient().Named("ChildService"));
//nearest in 3.2 container.Register(Component.For<Component2>().ImplementedBy<Component2>().LifestyleBoundToNearest<IChildService>());
//creates single instance of Component2 container.Register(Component.For<Component2>().ImplementedBy<Component2>().LifestyleBoundTo<ChildService>());
Func<IHandler[], IHandler> scopeRootBinder = ScopeRootBinder;
container.Register(Component.For<Component2>().ImplementedBy<Component2>().LifestyleBoundTo(scopeRootBinder));
container.Register(Component.For<Component3>().ImplementedBy<Component3>().LifestyleTransient());
var rs = container.Resolve<IRootService>();
var first = rs.ChildServices[0];
var second = rs.ChildServices[1];
ReferenceEquals(first, second).Should().BeFalse();
ReferenceEquals(first.Component2, second.Component2).Should().BeFalse("each child service should have its own Component2");
ReferenceEquals(first.Component2, first.Component3.Component2).Should().BeTrue();
ReferenceEquals(second.Component2, second.Component3.Component2).Should().BeTrue();
}
private IHandler ScopeRootBinder(IHandler[] handlers)
{
//not clear what should be here???
var r = handlers.FirstOrDefault(h => h.ComponentModel.Services.Any(t => t.Name == "IChildService"));
return r;
}
and here're the classes
public interface IRootService
{
IChildService[] ChildServices { get; }
}
public class RootService : IRootService
{
public RootService(IChildService[] childServices)
{
ChildServices = childServices;
}
public IChildService[] ChildServices { get; private set; }
}
public interface IChildService
{
Component3 Component3 { get; }
Component2 Component2 { get; }
}
public class ChildService: IChildService
{
public ChildService(Component2 comp, Component3 comp3)
{
Component2 = comp;
Component3 = comp3;
}
public Component3 Component3 { get; set; }
public Component2 Component2 { get; set; }
}
public class Component3
{
public Component3(Component2 comp)
{
Component2 = comp;
}
public Component2 Component2 { get; set; }
}
public class Component2
{
private Guid _guid = Guid.NewGuid();
}
Related
I am trying to test my project using ef 6. here is the situation: I have the mold class and have some generic services like GetAll,GetById,Create,Update, Delete. trying to test these methods using xUnit. Stuck in mocking.
public partial class TblPtsVMold :IMoldObject
{
public int MoldId { get; set; }
public string? MoldType { get; set; }
public string? Plant { get; set; }
}
public partial class PTSProdContext : DbContext
{
private IConfiguration _configuration { get; set; }
public PTSProdContext()
{
}
public PTSProdContext(DbContextOptions<PTSProdContext> options)
: base(options)
{
}
public virtual DbSet<TblPtsVMold> TblPtsVMolds { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer
(_configuration.GetConnectionString
(_configuration["EnvionmentString:ENVIRONMENT"]));
}
}
}
public class PTSContextFactory
{
public string DbConnectionString { get; set; }
public PTSContextFactory(string dbConnectionString)
{
DbConnectionString = dbConnectionString;
}
public PTSProdContext CreateDbContext()
{
DbContextOptionsBuilder<PTSProdContext> options = new DbContextOptionsBuilder<PTSProdContext>();
options.UseSqlServer(DbConnectionString);
return new PTSProdContext(options.Options);
}
public interface IDataService<T>
{
IEnumerable<T> GetAll();
IEnumerable<T> GetAllWithID(List<int> Ids);
T Get(int id);
T Create(T entity);
}
generic dataservice class
public class GenericDataService<T> : IDataService<T> where T : class, IDomainObject
{
public readonly PTSContextFactory _contextFactory;
public GenericDataService(PTSContextFactory contextFactory)
{
_contextFactory = contextFactory;
}
public GenericDataService()
{
}
public IEnumerable<T> GetAllWithID(List<int> Ids)
{
using (PTSProdContext context = _contextFactory.CreateDbContext())
{
IEnumerable<T> entities = context.Set<T>().Where(e => Ids.Contains(e.Id)).ToList();
if (entities == null)
{
WeakReferenceMessenger.Default.Send(new LookupExceptionMessage(string.Format("Can't find record.")));
return default;
}
return entities;
}
}
public IEnumerable<T> GetAll()
{
using (PTSProdContext context = _contextFactory.CreateDbContext())
{
IEnumerable<T> results = context.Set<T>().ToList();
if (results == null)
{
return default;
}
return results;
}
}
Test:
[Fact]
public void GetAll_TestClassObjectPassed_ProperMethodCalled()
{
// Arrange
var testObject = new TblPtsVMold() { Id = 1 };
var testList = new List<TblPtsVMold>() { testObject };
var data = new List<TblPtsVMold>
{
new TblPtsVMold { MoldType = "test",Plant="testpass1" },
new TblPtsVMold { MoldType = "ZZZ",Plant="testpass2" },
new TblPtsVMold { MoldType = "AAA",Plant="testpass3" },
}.AsQueryable();
var dbSetMock = new Mock<DbSet<TblPtsVMold>>();
dbSetMock.As<IQueryable<TblPtsVMold>>().Setup(x => x.Provider).Returns(testList.AsQueryable().Provider);
dbSetMock.As<IQueryable<TblPtsVMold>>().Setup(x => x.Expression).Returns(testList.AsQueryable().Expression);
dbSetMock.As<IQueryable<TblPtsVMold>>().Setup(x => x.ElementType).Returns(testList.AsQueryable().ElementType);
dbSetMock.As<IQueryable<TblPtsVMold>>().Setup(x => x.GetEnumerator()).Returns(testList.AsQueryab`your text`le().GetEnumerator());
var context = new Mock<PTSProdContext>();
context.Setup(x => x.Set<TblPtsVMold>()).Returns(dbSetMock.Object);
// Act
var context = new Mock<PTSContextFactory>();
context.Setup(x => x.DbConnectionString).Returns(string.Empty);
var service = new GenericDataService<TblPtsVMold>(context.Object);
var result = service.GetAll();
// Assert
Assert.Equal(testList, result.ToList());
}
context.Setup(x => x.DbConnectionString).Returns(string.Empty); is not correct.
getting error:pportedException : Unsupported expression: x => x.DbConnectionString Non-overridable members (here: PTSContextFactory.get_DbConnectionString) may not be used in setup verification expressions.
How to test GetAll or create method. Is anything wrong here?
I am getting this rare exception when I am trying to update an entity. I am working with ASP.NET MVC 5, EF 6.1, Identity and the patterns repository and unit of work.
I followed this cool tutorial from Tim.
I have all the work done in 4 separate projects (UI, Entities, Domain and DataAccess), I included Tim solution to use Users and roles.
My Entities:
public class Turno : IEntity
{
public Turno()
{
//Medico = new Medico();
//Consultorio = new Consultorio();
}
public Int64 Id { get; set; }
[Required]
public DateTime Fecha { get; set; }
[Required]
[StringLength(10)]
public string Hora { get; set; }
[Required]
public Medico Medico { get; set; }
[Required]
public Consultorio Consultorio { get; set; }
[Required]
public EstadoTurno Estado { get; set; }
public virtual Paciente Paciente { get; set; }
}
namespace TurnosMedicos.Entities
{
[Table("Medicos")]
public class Medico: Persona
{
public Medico()
{
Especialidades = new List<Especialidad>();
TurnosDisponibles = new List<Turno>();
Consultorios = new List<Consultorio>();
Telefonos = new List<Telefono>();
PlanesAtendidos = new List<PrepagaPlan>();
}
[Required]
[StringLength(10)]
public string Matricula { get; set; }
[Required]
public decimal PrecioTurno { get; set; }
public virtual List<Especialidad> Especialidades { get; set; }
public virtual List<Turno> TurnosDisponibles { get; set; }
public virtual List<Consultorio> Consultorios { get; set; }
public List<PrepagaPlan> PlanesAtendidos { get; set; }
public override string ToString()
{
return Apellido + ", " + Nombres;
}
}
}
namespace TurnosMedicos.Entities
{
public class Paciente: Persona
{
public Paciente()
{
HistoriaClinica = new List<Consulta>();
Turnos = new List<Turno>();
Telefonos = new List<Telefono>();
PlanesSalud = new List<PrepagaPlan>();
TurnosAusentes = new List<TurnoInformadoAusente>();
}
public virtual List<TurnoInformadoAusente> TurnosAusentes { get; set; }
public virtual List<Consulta> HistoriaClinica { get; set; }
public virtual List<Turno> Turnos { get; set; }
public override string ToString()
{
return Apellido + ", " + Nombres;
}
public List<PrepagaPlan> PlanesSalud { get; set; }
public PrepagaPlan PlanPredeterminado()
{
if(PlanesSalud.Count()>0)
{
return PlanesSalud[0];
}
return null;
}
public string TelefonosRapido()
{
System.Text.StringBuilder tel = new System.Text.StringBuilder();
foreach(var t in this.Telefonos)
{
tel.Append(t.Numero + " (" + t.Tipo + ")");
tel.AppendLine();
}
return tel.ToString();
}
/// <summary>
/// Porcentaje de Asistencia
/// </summary>
[NotMapped]
public decimal Ranking
{
get{
if (TurnosAusentes.Count == 0)
{
return 100;
}
else{
return (100 - (Decimal.Divide(TurnosAusentes.Count, Turnos.Count) * 100));
}
}
}
}
}
My Repositories:
public class MedicosRepository: Repository<Medico> //, IMedicoRepository
{
internal MedicosRepository(ApplicationDbContext context)
: base(context)
{
}
public IQueryable<Medico> Find(System.Linq.Expressions.Expression<Func<Medico, bool>> predicate)
{
return Set.Where(predicate);
}
public override List<Medico> GetAll()
{
return Set.Include("Telefonos")
.Include("PlanesAtendidos")
.Include("Consultorios")
.Include("Consultorios.Telefonos")
.Include("TurnosDisponibles.Paciente.Telefonos")
.ToList();
}
public IQueryable<Medico> FindAll()
{
return Set.Include("Telefonos")
.Include("PlanesAtendidos")
.Include("Consultorios")
.Include("Consultorios.Telefonos")
.Include("TurnosDisponibles.Paciente.Telefonos");
}
public override Medico FindById(object id)
{
Int64 Id = Int64.Parse(id.ToString());
return Set.Include("Telefonos")
.Include("Consultorios")
.Include("Consultorios.Telefonos")
.Include("PlanesAtendidos")
.Include("TurnosDisponibles.Paciente.Telefonos")
.Single(o => o.Id == Id);
}
}
TurnosRepository:
namespace TurnosMedicos.DataAccess.Repositories
{
internal class TurnosRepository: Repository<Turno>
{
public TurnosRepository(ApplicationDbContext context): base(context)
{
}
public override List<Turno> GetAll()
{
return Set.Include("Medico")
.Include("Paciente")
.Include("Consultorio").ToList();
}
public override Turno FindById(object id)
{
Int64 Id = Int64.Parse(id.ToString());
return Set.Include("Medico")
.Include("Paciente")
.Include("Consultorio")
.Single(o => o.Id == Id);
}
}
}
User repository:
namespace TurnosMedicos.DataAccess.Repositories
{
internal class UserRepository : Repository<User>, IUserRepository
{
internal UserRepository(ApplicationDbContext context)
: base(context)
{
}
public User FindByUserName(string userName)
{
return Set.Include("Medico")
.Include("Paciente")
.FirstOrDefault(x => x.UserName == userName);
}
public Task<User> FindByUserNameAsync(string userName)
{
return Set.FirstOrDefaultAsync(x => x.UserName == userName);
}
public Task<User> FindByEmailAsync(System.Threading.CancellationToken cancellationToken, string email)
{
return Set.FirstOrDefaultAsync(x => x.Email == email, cancellationToken);
}
public User FindByEmail(string email)
{
return Set.Include("Medico")
.Include("Medico.Telefonos")
.Include("Medico.Especialidades")
.Include("Medico.TurnosDisponibles")
.Include("Medico.Consultorios")
.Include("Medico.PlanesAtendidos")
.Include("Paciente")
.Include("Paciente.Turnos")
.Include("Paciente.PlanesSalud")
.Include("Paciente.HistoriaClinica")
.Include("Paciente.TurnosAusentes")
.Include("Paciente.Telefonos")
.Include("Roles")
.FirstOrDefault(u => u.Email == email);
}
}
}
My Context:
namespace TurnosMedicos.DataAccess
{
internal class ApplicationDbContext : DbContext
{
internal ApplicationDbContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
public ApplicationDbContext(): base("TurnosMedicosCn")
{
}
public IDbSet<User> Users { get; set; }
public IDbSet<Role> Roles { get; set; }
public IDbSet<ExternalLogin> Logins { get; set; }
public DbSet<Paciente> Pacientes { get; set; }
public DbSet<Medico> Medicos { get; set; }
public DbSet<Turno> Turnos { get; set; }
public DbSet<Consulta> Consultas { get; set; }
public DbSet<Consultorio> Consultorios { get; set; }
public DbSet<Especialidad> Especialidades { get; set; }
public DbSet<Prepaga> Prepagas { get; set; }
public DbSet<PrepagaPlan> Planes { get; set; }
public DbSet<Registro> RegistrosFacturacion { get; set; }
public DbSet<Empresa> Empresas { get; set; }
public DbSet<Recomendado> Recomendados { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserConfiguration());
modelBuilder.Configurations.Add(new RoleConfiguration());
modelBuilder.Configurations.Add(new ExternalLoginConfiguration());
modelBuilder.Configurations.Add(new ClaimConfiguration());
}
}
}
My Unit Of Work
namespace TurnosMedicos.DataAccess
{
public class SQLUnitOfWork: IUnitOfWork
{
private readonly ApplicationDbContext _context;
PacientesRepository _pacientes = null;
//MedicosRepository _medicos = null;
IRepository<Medico> _medicos = null;
TurnosRepository _turnos = null;
EspecialidadRepository _especialidades = null;
PrepagasRepository _prepagas = null;
PrepagaPlanesRepository _planes = null;
RegistrosFacturacionRepository _registroFacturacion = null;
RecomendadosRepository _recomendados = null;
private IExternalLoginRepository _externalLoginRepository;
private IRoleRepository _roleRepository;
private IUserRepository _userRepository;
public SQLUnitOfWork(string nameOrConnectionString)
{
_context = new ApplicationDbContext(nameOrConnectionString);
}
public IRepository<Turno> Turnos
{
get { return _turnos ?? (_turnos = new TurnosRepository(_context)); }
}
public IRepository<Paciente> Pacientes
{
get
{
if(_pacientes==null)
{
_pacientes = new PacientesRepository(_context);
}
return _pacientes;
}
}
public IRepository<Medico> Medicos
{
get { return _medicos ?? (_medicos = new MedicosRepository(_context)); }
}
public IRepository<Especialidad> Especialidades
{
get
{
if (_especialidades == null)
{
_especialidades = new EspecialidadRepository(_context);
}
return _especialidades;
}
set
{
throw new NotImplementedException();
}
}
public IRepository<Prepaga> Prepagas {
get {
if (_prepagas == null)
{
_prepagas = new PrepagasRepository(_context);
}
return _prepagas;
}
set { throw new NotImplementedException(); }
}
public IRepository<PrepagaPlan> Planes {
get
{
if (_planes == null)
{
_planes = new PrepagaPlanesRepository(_context);
}
return _planes;
}
}
public IRepository<Registro> RegistrosFacturacion
{
get
{
if(_registroFacturacion == null)
{
_registroFacturacion = new RegistrosFacturacionRepository(_context);
}
return _registroFacturacion;
}
}
public IRepository<Recomendado> Recomendados
{
get
{
if (_recomendados == null)
{
_recomendados = new RecomendadosRepository(_context);
}
return _recomendados;
}
}
public IExternalLoginRepository ExternalLoginRepository
{
get { return _externalLoginRepository ?? (_externalLoginRepository = new ExternalLoginRepository(_context)); }
}
public IRoleRepository RoleRepository
{
get { return _roleRepository ?? (_roleRepository = new RoleRepository(_context)); }
}
public IUserRepository UserRepository
{
get { return _userRepository ?? (_userRepository = new UserRepository(_context)); }
}
public int SaveChanges()
{
try
{
return _context.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
Exception raise = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
raise = new InvalidOperationException(message, raise);
}
}
throw raise;
}
}
public Task<int> SaveChangesAsync()
{
try
{
return _context.SaveChangesAsync();
}
catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
{
Exception raise = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
string message = string.Format("{0}:{1}",
validationErrors.Entry.Entity.ToString(),
validationError.ErrorMessage);
raise = new InvalidOperationException(message, raise);
}
}
throw raise;
}
}
public Task<int> SaveChangesAsync(System.Threading.CancellationToken cancellationToken)
{
return _context.SaveChangesAsync(cancellationToken);
}
public void Dispose()
{
_externalLoginRepository = null;
_roleRepository = null;
_userRepository = null;
_turnos = null;
_pacientes = null;
_especialidades = null;
_planes = null;
_prepagas = null;
_recomendados = null;
_registroFacturacion = null;
}
}
}
And Finally, the Domain class where I am trying to get things done
IUnitOfWork unitofwork = null;
IRepository<Paciente> repositoryPacientes = null;
//IMedicoRepository repositoryMedicos = null;
IRepository<Medico> repositoryMedicos = null;
IRepository<Turno> repositoryTurnos = null;
IRepository<Especialidad> repositoryEspecialidad = null;
IRepository<Registro> repositoryRegistroFacturacion = null;
IRepository<Recomendado> repositoryRecomendados = null;
public TurnosManager(IUnitOfWork _unitOfWork)
{
unitofwork = _unitOfWork;
repositoryPacientes = unitofwork.Pacientes;
repositoryMedicos = unitofwork.Medicos;
repositoryTurnos = unitofwork.Turnos;
repositoryEspecialidad = unitofwork.Especialidades;
repositoryRegistroFacturacion = unitofwork.RegistrosFacturacion;
repositoryRecomendados = unitofwork.Recomendados;
}
private bool AsignarTurno(Paciente p, Turno t)
{
if(t.Fecha.Date < DateTime.Now.Date)
{
throw new TurnoInvalidoException("No se puede seleccionar un turno para una fecha en el pasado.");
}
// Ver tema de la hora para la fecha actual
t.Estado = EstadoTurno.Reservado;
t.Paciente = p;
p.Turnos.Add(t);
//repositoryTurnos.Update(t);
unitofwork.SaveChanges();
string planMedico = "Privado";
if (p.PlanesSalud.Count > 0)
{
planMedico = p.PlanesSalud[0].NombrePlan;
}
RegisstrarParaFacturacion(t, planMedico);
ReservaVM obj = new ReservaVM();
obj.Paciente = p;
obj.MedicoSeleccionado = t.Medico;
obj.TurnoSeleccionado = t;
EnviarEmail(obj);
return true;
}
The problem occurs in line unitofwork.SaveChanges();
I get the exception: "You can not define the relationship between two objects because they are associated with different ObjectContext objects" but I only have "ApplicationDbContext" in my code.
The problem is that you have one type which is ApplicationDbContext, but there are two instances of that context. One instantiated to fetch Pacient p and another one for Turno t.
Where is the AsignarTurno(Paciente p, Turno t) called from?
If this is code first you should add
public int PacienteId { get; set; }
to class Turno.
If your classes are well define you should only need to persist the relation on one side, so in the AsignarTurno function instead of:
t.Paciente = p;
p.Turnos.Add(t);
you should only have
t.PacienteId = p.Id;
This would do what you need, assuming that p and t both exist the database.
I have a Model :
public class Post:
{
public string Description { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public Guid UniqId { get; set; }
public DateTime CreatedDate { get; set; }
public byte[] RowVersion { get; set; }
}
and i have a DataLayer that has EfContext and Iunitofwok pattern
using System.Data.Entity;
namespace Data
{
public interface IUnitOfWork
{
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
}
using System.Data.Entity;
using DomainModel;
namespace Data
{
public class EfContext : DbContext, IUnitOfWork
{
public DbSet<Post> Post { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<Category> Categories { get; set; }
public EfContext()
: base("TavanGruop")
{
}
#region IUnitOfWork Members
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
#endregion
}
}
in another project i have repository
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using Data;
namespace ServiceLayer.ServiceDbSet
{
public class ServiceContext<T> : IServiceDbSet<T> where T : class
{
private readonly IDbSet<T> _dbSet;
public ServiceContext(IUnitOfWork iUnitOfWork)
{
_dbSet = iUnitOfWork.Set<T>();
}
#region IContext<T> Members
public bool TryGet(Func<T, bool> predicate, out T entity)
{
entity = List(predicate).SingleOrDefault();
return entity != null;
}
public T Get(Func<T, bool> predicate)
{
return List(predicate).Single();
}
public virtual List<T> List(Func<T, bool> predicate = null)
{
IEnumerable<T> result = _dbSet.AsEnumerable();
if (predicate != null)
result = result.Where(predicate);
return result.ToList();
}
public T Add(T t)
{
_dbSet.Add(t);
return t;
}
public void Delete(Func<T, bool> predicate)
{
List(predicate).ToList().ForEach(p => _dbSet.Remove(p));
}
public void Delete(T t)
{
_dbSet.Remove(t);
}
#endregion
}
}
and service
using Data;
using DomainModel;
using ServiceLayer.ServiceDbSet;
namespace ServiceLayer.EfServices
{
public class EfPostService : ServiceContext<Post>
{
public EfPostService(IUnitOfWork uow)
: base(uow)
{
}
}
}
and this my services
using Data;
using ServiceLayer.EfServices;
namespace ServiceLayer
{
public class Services
{
private readonly IUnitOfWork _unitOfWork;
private EfPostService _post;
private EfCommentService _comment;
public Services(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public EfPostService Post
{
get { return _post ?? new EfPostService(_unitOfWork); }
set { _post = value; }
}
public EfCommentService Comment
{
get { return _comment ?? new EfCommentService(_unitOfWork); }
set { _comment = value; }
}
}
}
I use tructuremap for dependency injection
using System;
using System.Web.Mvc;
using System.Web.Routing;
using Data;
using StructureMap;
namespace MVCTemplateProject
{
public static class StructuremapMvc
{
public static void InitStructureMap()
{
ObjectFactory.Initialize(x => x.For<IUnitOfWork>().HttpContextScoped().Use(() => new EfContext()));
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
}
}
public class StructureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return ObjectFactory.GetInstance(controllerType) as Controller;
}
}
}
in base controller i get Iunitofwork
using System.Web.Mvc;
using Data;
using ServiceLayer;
namespace MVCTemplateProject.Controllers
{
public class BaseController : Controller
{
public readonly IUnitOfWork Context;
public readonly Services DataContext;
public BaseController(Data.IUnitOfWork context)
{
Context = context;
DataContext = new Services(context);
}
}
}
and this my home controller
using System.Web.Mvc;
using Data;
using DomainModel;
namespace MVCTemplateProject.Controllers
{
public class HomeController : BaseController
{
public HomeController(IUnitOfWork context)
: base(context)
{
}
public ActionResult Index()
{
return View(DataContext.Post.List());
}
}
}
how can i test index action with moq
i write this test but i get error
public void IndxShouldReturnListOfPage()
{
var posts = new List<Post>
{
new Post {Name = "Test"},
new Post {Name = "Test"},
new Post {Name = "Test"},
new Post {Name = "Test"}
};
var efContext = new Mock<EfContext>();
var mockRepository = new Mock<ServiceLayer.Services>(efContext);
mockRepository.Setup(x => x.Post.List(It.IsAny<Func<Post, bool>>())).Returns(posts);
var controller = new HomeController(efContext.Object);
List<Post> model = controller.DataContext.Post.List();
var result = controller.Index() as ViewResult;
Assert.AreEqual(model.Count, 4);
Assert.AreEqual(string.Empty, result.ViewName);
}
i get it and i test the project
[TestFixture]
public class PostControllerTest
{
#region Setup/Teardown
[SetUp]
public void Setup()
{
UnitOfWork = TestHelper.TestHelper.GetMockUnitOfWork();
PostDbSet = TestHelper.TestHelper.GetMockPostDbSet();
Posts = TestHelper.TestHelper.GetFakePosts();
TagDbSet = TestHelper.TestHelper.GetMockTagDbSet();
CategoryDbSet = TestHelper.TestHelper.GetMockCategoryDbSet();
PostController = new PostController(UnitOfWork.Object, PostDbSet.Object, CategoryDbSet.Object, TagDbSet.Object);
}
#endregion
private Mock<IServiceDbSet<Post>> PostDbSet { get; set; }
private Mock<IServiceDbSet<Tag>> TagDbSet { get; set; }
private Mock<IServiceDbSet<Category>> CategoryDbSet { get; set; }
private PostController PostController { get; set; }
private List<Post> Posts { get; set; }
private Mock<IUnitOfWork> UnitOfWork { get; set; }
[Test]
public void DetailShouldRedirectToHomePageWhenNotFoundPostOrPostIdIs0()
{
PostDbSet.Setup(x => x.Get(It.IsAny<Func<Post, bool>>())).Returns(Posts.Find(post => post.Id == 100));
var redirectToRoutResult =
(RedirectToRouteResult) PostController.Details(100);
Assert.AreEqual("Index", redirectToRoutResult.RouteValues["action"]);
Assert.AreEqual("Home", redirectToRoutResult.RouteValues["Controller"]);
}
[Test]
public void DetailShouldShowPostById()
{
PostDbSet.Setup(x => x.Get(It.IsAny<Func<Post, bool>>())).Returns(Posts.First());
var result = PostController.Details(1) as ViewResult;
var model = result.Model as PostViewModel;
Assert.AreNotEqual(null, model);
Assert.AreEqual("I Can", model.Title);
Assert.AreEqual(string.Empty, result.ViewName);
}
[Test]
public void ListOfStringTagMustConvertToListOfTagCollection()
{
PostViewModel postViewModel = TestHelper.TestHelper.GetFakePostViewModel();
PostController.Create(postViewModel);
//Assert.AreEqual(postViewModel.RawTags[0], postViewModel.RawTags.First().Name);
}
I'm trying out Entity Framework Code first CTP4. Suppose I have:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public Parent Mother { get; set; }
}
public class TestContext : DbContext
{
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
}
public class ChildEdit
{
public int Id { get; set; }
public string Name { get; set; }
public int MotherId { get; set; }
}
Mapper.CreateMap<Child, ChildEdit>();
Mapping to the Edit model is not a problem. On my screen I select the mother through some control (dropdownlist, autocompleter, etc) and the Id of the mother gets posted in back:
[HttpPost]
public ActionResult Edit(ChildEdit posted)
{
var repo = new TestContext();
var mapped = Mapper.Map<ChildEdit, Child>(posted); // <------- ???????
}
How should I solve the last mapping? I don't want to put Mother_Id in the Child object. For now I use this solution, but I hope it can be solved in Automapper.
Mapper.CreateMap<ChildEdit, Child>()
.ForMember(i => i.Mother, opt => opt.Ignore());
var mapped = Mapper.Map<ChildEdit, Child>(posted);
mapped.Mother = repo.Parents.Find(posted.MotherId);
EDIT
This works, but now I have to do that for each foreign key (BTW: context would be injected in final solution):
Mapper.CreateMap<ChildEdit, Child>();
.ForMember(i => i.Mother,
opt => opt.MapFrom(o =>
new TestContext().Parents.Find(o.MotherId)
)
);
What I'd really like would be:
Mapper.CreateMap<int, Parent>()
.ForMember(i => i,
opt => opt.MapFrom(o => new TestContext().Parents.Find(o))
);
Mapper.CreateMap<ChildEdit, Child>();
Is that possible with Automapper?
First, I'll assume that you have a repository interface like IRepository<T>
Afterwards create the following class:
public class EntityConverter<T> : ITypeConverter<int, T>
{
private readonly IRepository<T> _repository;
public EntityConverter(IRepository<T> repository)
{
_repository = repository;
}
public T Convert(ResolutionContext context)
{
return _repository.Find(System.Convert.ToInt32(context.SourceValue));
}
}
Basically this class will be used to do all the conversion between an int and a domain entity. It uses the "Id" of the entity to load it from the Repository. The IRepository will be injected into the converter using an IoC container, but more and that later.
Let's configure the AutoMapper mapping using:
Mapper.CreateMap<int, Mother>().ConvertUsing<EntityConverter<Mother>>();
I suggest creating this "generic" mapping instead so that if you have other references to "Mother" on other classes they're mapped automatically without extra-effort.
Regarding the Dependency Injection for the IRepository, if you're using Castle Windsor, the AutoMapper configuration should also have:
IWindsorContainer container = CreateContainer();
Mapper.Initialize(map => map.ConstructServicesUsing(container.Resolve));
I've used this approach and it works quite well.
Here's how I did it: (using ValueInjecter)
I made the requirements a little bigger just to show how it works
[TestFixture]
public class JohnLandheer
{
[Test]
public void Test()
{
var child = new Child
{
Id = 1,
Name = "John",
Mother = new Parent { Id = 3 },
Father = new Parent { Id = 9 },
Brother = new Child { Id = 5 },
Sister = new Child { Id = 7 }
};
var childEdit = new ChildEdit();
childEdit.InjectFrom(child)
.InjectFrom<EntityToInt>(child);
Assert.AreEqual(1, childEdit.Id);
Assert.AreEqual("John", childEdit.Name);
Assert.AreEqual(3, childEdit.MotherId);
Assert.AreEqual(9, childEdit.FatherId);
Assert.AreEqual(5, childEdit.BrotherId);
Assert.AreEqual(7, childEdit.SisterId);
Assert.AreEqual(0, childEdit.Sister2Id);
var c = new Child();
c.InjectFrom(childEdit)
.InjectFrom<IntToEntity>(childEdit);
Assert.AreEqual(1, c.Id);
Assert.AreEqual("John", c.Name);
Assert.AreEqual(3, c.Mother.Id);
Assert.AreEqual(9, c.Father.Id);
Assert.AreEqual(5, c.Brother.Id);
Assert.AreEqual(7, c.Sister.Id);
Assert.AreEqual(null, c.Sister2);
}
public class Entity
{
public int Id { get; set; }
}
public class Parent : Entity
{
public string Name { get; set; }
}
public class Child : Entity
{
public string Name { get; set; }
public Parent Mother { get; set; }
public Parent Father { get; set; }
public Child Brother { get; set; }
public Child Sister { get; set; }
public Child Sister2 { get; set; }
}
public class ChildEdit
{
public int Id { get; set; }
public string Name { get; set; }
public int MotherId { get; set; }
public int FatherId { get; set; }
public int BrotherId { get; set; }
public int SisterId { get; set; }
public int Sister2Id { get; set; }
}
public class EntityToInt : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType.IsSubclassOf(typeof(Entity)) && targetType == typeof(int);
}
protected override string TargetPropName(string sourcePropName)
{
return sourcePropName + "Id";
}
protected override bool AllowSetValue(object value)
{
return value != null;
}
protected override object SetValue(object sourcePropertyValue)
{
return (sourcePropertyValue as Entity).Id;
}
}
public class IntToEntity : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType == typeof(int) && targetType.IsSubclassOf(typeof(Entity));
}
protected override string TargetPropName(string sourcePropName)
{
return sourcePropName.RemoveSuffix("Id");
}
protected override bool AllowSetValue(object value)
{
return (int)value > 0;
}
protected override object SetValue(object sourcePropertyValue)
{
// you could as well do repoType = IoC.Resolve(typeof(IRepo<>).MakeGenericType(TargetPropType))
var repoType = typeof (Repo<>).MakeGenericType(TargetPropType);
var repo = Activator.CreateInstance(repoType);
return repoType.GetMethod("Get").Invoke(repo, new[] {sourcePropertyValue});
}
}
class Repo<T> : IRepo<T> where T : Entity, new()
{
public T Get(int id)
{
return new T{Id = id};
}
}
private interface IRepo<T>
{
T Get(int id);
}
}
It's possible to define the foreign key in EF this way as well:
[ForeignKey("MotherId")]
public virtual Parent Mother { get; set; }
public int MotherId { get; set; }
In this case, It's not necessary to do an extra query to find the Mother. Just Assign the ViewModel's MotherId to the Model's MotherId.
I'm trying to implement the Strategy pattern while using Windsor container. Here is what I have:
public class OrderProcessor {
...
public OrderProcessor(ITaxStrategy strategy) {}
public void Process(Order order)
{
order.Tax = strategy.CalcTax(order);
}
}
The problem is, how do I configure my container (other container examples welcome) to have, essentially, criteria for choosing the appropriate dependency. So if I register the following
public class USTaxStrategy : ITaxStrategy { ... }
public class CanadaTaxStrateg : ITaxStrategy { ... }
how do I use the Order.Destination (address) as the criteria for the injected dependency?
Here are a few options, pick the one you like best. I usually use the first one, it's the simplest.
[TestFixture]
public class TaxStrategyTests {
[Test]
public void InjectWithFactory() {
var container = new WindsorContainer();
container.AddComponent<USTaxStrategy>();
container.AddComponent<CanadaTaxStrategy>();
container.AddComponent<OrderProcessor>();
container.AddComponent<ITaxStrategyFactory, TaxStrategyFactory>();
var order = new Order {Country = "US"};
container.Resolve<OrderProcessor>().Process(order);
Assert.AreEqual(10, order.Tax);
}
[Test]
public void InjectWithFactoryFromDictionary() {
var container = new WindsorContainer();
container.AddFacility<FactorySupportFacility>();
container.AddComponent<USTaxStrategy>();
container.AddComponent<CanadaTaxStrategy>();
container.AddComponent<OrderProcessor>();
container.Register(Component.For<ITaxStrategyFactory>()
.UsingFactoryMethod(kernel => new TaxStrategyFactory2(new Dictionary<string, ITaxStrategy> {
{"US", kernel.Resolve<USTaxStrategy>()},
{"CA", kernel.Resolve<CanadaTaxStrategy>()},
})));
var order = new Order { Country = "US" };
container.Resolve<OrderProcessor>().Process(order);
Assert.AreEqual(10, order.Tax);
}
[Test]
public void InjectWithProxy() {
var container = new WindsorContainer();
container.AddComponent<USTaxStrategy>();
container.AddComponent<CanadaTaxStrategy>();
container.AddComponent<OrderProcessorInterceptor>();
container.AddComponent<ITaxStrategyFactory, TaxStrategyFactory>();
container.Register(Component.For<OrderProcessor2>()
.LifeStyle.Transient
.Interceptors(InterceptorReference.ForType<OrderProcessorInterceptor>()).First);
var order = new Order {Country = "CA"};
container.Resolve<OrderProcessor2>().Process(order);
Assert.AreEqual(5, order.Tax);
}
public class OrderProcessorInterceptor : IInterceptor {
private readonly ITaxStrategyFactory strategyFactory;
public OrderProcessorInterceptor(ITaxStrategyFactory strategyFactory) {
this.strategyFactory = strategyFactory;
}
public void Intercept(IInvocation invocation) {
if (invocation.MethodInvocationTarget.Name == "Process") {
var processor = (OrderProcessor2) invocation.InvocationTarget;
var order = (Order) invocation.Arguments[0];
processor.Strategy = strategyFactory.Create(order);
}
invocation.Proceed();
}
}
public interface IOrderProcessor {
void Process(Order order);
}
public class OrderProcessor2 : IOrderProcessor {
public ITaxStrategy Strategy { get; set; }
public virtual void Process(Order order) {
order.Tax = Strategy.CalcTax(order);
}
}
public class OrderProcessor : IOrderProcessor {
private readonly ITaxStrategyFactory strategyFactory;
public OrderProcessor(ITaxStrategyFactory strategyFactory) {
this.strategyFactory = strategyFactory;
}
public void Process(Order order) {
var strategy = strategyFactory.Create(order);
order.Tax = strategy.CalcTax(order);
}
}
public interface ITaxStrategyFactory {
ITaxStrategy Create(Order o);
}
public class TaxStrategyFactory : ITaxStrategyFactory {
private readonly IKernel kernel;
public TaxStrategyFactory(IKernel kernel) {
this.kernel = kernel;
}
public ITaxStrategy Create(Order o) {
if (o.Country == "US")
return kernel.Resolve<USTaxStrategy>();
return kernel.Resolve<CanadaTaxStrategy>();
}
}
public class TaxStrategyFactory2: ITaxStrategyFactory {
private readonly IDictionary<string, ITaxStrategy> strategies;
public TaxStrategyFactory2(IDictionary<string, ITaxStrategy> strategies) {
this.strategies = strategies;
}
public ITaxStrategy Create(Order o) {
return strategies[o.Country];
}
}
public interface ITaxStrategy {
decimal CalcTax(Order order);
}
public class USTaxStrategy : ITaxStrategy {
public decimal CalcTax(Order order) {
return 10;
}
}
public class CanadaTaxStrategy : ITaxStrategy {
public decimal CalcTax(Order order) {
return 5;
}
}
public class Order {
public string Country { get; set; }
public decimal Tax { get; set; }
}
}