This is my test:
[TestMethod]
public void TestUnitOfWork()
{
UnitOfWork unitOfWork = new UnitOfWork();
unitOfWork.ContactRepository.Insert(new Contact
{
Id = Guid.NewGuid(),
FirstName = "Dom",
LastName = "A",
Email = "dominicarchual#yahoo.com"
});
var contacts = unitOfWork.ContactRepository.Get(x => x.FirstName == "Dominic");
Assert.AreEqual(1, contacts.Count());
}
The error I get is:
Test method
MvcContacts.Tests.Controllers.HomeControllerTest.TestUnitOfWork threw
exception: System.Data.ProviderIncompatibleException: An error
occurred while getting provider information from the database. This
can be caused by Entity Framework using an incorrect connection
string. Check the inner exceptions for details and ensure that the
connection string is correct. --->
System.Data.ProviderIncompatibleException: The provider did not return
a ProviderManifestToken string. --->
System.Data.SqlClient.SqlException: A network-related or
instance-specific error occurred while establishing a connection to
SQL Server. The server was not found or was not accessible. Verify
that the instance name is correct and that SQL Server is configured to
allow remote connections. (provider: SQL Network Interfaces, error: 26
- Error Locating Server/Instance Specified)
I don't have any database set up; i.e. my context looks like this:
namespace MvcContacts.DAL
{
public class ContactsContext : DbContext
{
public DbSet<Contact> Contacts { get; set; }
}
}
I don't know exactly how to map this to my database; but, I was thinking that I wouldn't have to do that yet since I am just trying to test using mock data. Am I wrong?
E1: This is my unit of work class.
namespace MvcContacts.DAL
{
public class UnitOfWork : IDisposable
{
private ContactsContext context = new ContactsContext();
private GenericRepository<Contact> contactRepository;
public GenericRepository<Contact> ContactRepository
{
get
{
if (this.contactRepository == null)
{
this.contactRepository = new GenericRepository<Contact>(context);
}
return contactRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
As i said, the problem is that you are actually calling real database inside your UnitOfWork. I'm pretty sure, your GenericRepository<> class just wraps DbSet inside your context. Here is where you create the 'real' database accessor.
private ContactsContext context = new ContactsContext();
But the problem is you misunderstand the whole concept of repositories. Unit of work is an abstraction of some data source. You should not unit test the abstraction, instead you should unit test some functionality which depends upon it. By the way, DbContext itself is a Unit of work by that definition (from martinfowler.com):
Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.
Why don't people just leave it as it is? Because there is a flaw in it. Let me explain by example. Seems like you're learning ASP.Net MVC so let's write some controller:
public class ContactsController
{
public ActionResult Index(int pageSize, int currentPage)
{
using(var db = new MvcLearningContext())
{
var contacts = db.Contacts
.Skip((currentPage - 1) * pageSize)
.Take(pageSize)
.ToList();
return View(contacts);
}
}
}
As you may know, one of the great advantages of MVC is the ability to unit test controller logic. So, let's try to write a simple unit test to make sure out controller action doesn't return more entries than the given page size:
[TestMethod]
public void IndexShouldNotReturnMoreThanPageSizeResults()
{
// arrange
var controller = new ContactsController();
// act
var view = (ViewResult) controller.Index(10, 1);
// assert
var Model = (IEnumerable<Contact>) view.Model;
Assert.IsTrue(view.Model.Count() <= 10)
}
But wait... We do not want to query the real database in the unit test. Here comes the problem with EF's DbContext: it completely depends on real database. But how can we avoid that? UnitOfWork comes in play:
public class ContactsController
{
private UnitOfWorkFactoryBase _factory { get; set; }
public ContactsController(UnitOfWorkFactoryBase factory)
{
factory = _factory;
}
public ActionResult Index(int pageSize, int currentPage)
{
using(var db = _factory.Create())
{
var contacts = db.Contacts
.Skip((currentPage - 1) * pageSize)
.Take(pageSize)
.ToList();
return View(contacts);
}
}
}
unit test code:
[TestMethod]
public void IndexShouldNotReturnMoreThanPageSizeResults()
{
// arrange
var factory = new MockUnitOfWorkFactory();
var controller = new ContactsController(factory);
// act
var view = (ViewResult) controller.Index(10, 1);
// assert
var Model = (IEnumerable<Contact>) view.Model;
Assert.IsTrue(view.Model.Count() <= 10)
}
and in production you replace MockUnitOfWorkFactory with UnitOfWorkFactory
UPD: basic implementation of factories:
public abstract class UnitOfWorkFactoryBase
{
public abstract UnitOfWorkBase Create();
}
public class UnitOfWorkFactory : UnitOfWorkFactoryBase
{
public override UnitOfWorkBase Create()
{
return new UnitOfWork();
}
}
public class MockUnitOfWorkFactory : UnitOfWorkFactoryBase
{
public override UnitOfWorkBase Create()
{
return new MockUnitOfWork();
}
}
UnitOfWork and MockUnitOfWork are implementations of UnitOfWorkBase abstract class.
Related
I'm new to unit testing, so my problem is probably with my code and not the Moq framework, but here goes.
I'm using .Net Core with xUnit and the Moq framework, and I'm more or less following instructions from their documentation. I'm trying to test route api/user to get all users, and the issue was on asserting that the response was an ObjectResult containing <IEnumerable<User>>. No matter what I tried, result.Value was always null. The first assertion passes fine.
I set up a console project to debug this, and found something interesting. that value of the controller in the test method in Visual Studio is null. In VS Code, the value in the debugger shows Unknown Error: 0x00000....
Below is the test:
public class UserControllerTests {
[Fact]
public void GetAll_ReturnsObjectResult_WithAListOfUsers() {
// Arrange
var mockService = new Mock<IUserService>();
var mockRequest = new Mock<IServiceRequest>();
mockService.Setup(svc => svc.GetUsers(mockRequest.Object))
.Returns(new ServiceRequest(new List<User> { new User() }));
var controller = new UserController(mockService.Object);
// Act
var result = controller.GetAll();
// Assert
Assert.IsType<ObjectResult>(result);
Assert.IsAssignableFrom<IEnumerable<User>>(((ObjectResult)result).Value);
}
}
And here is the controller:
public class UserController : Controller {
private IUserService service;
public UserController(IUserService service) {
this.service = service;
}
[HttpGet]
public IActionResult GetAll() {
var req = new ServiceRequest();
service.GetUsers(req);
if(req.Errors != null) return new BadRequestObjectResult(req.Errors);
return new ObjectResult(req.EntityCollection);
}
}
And the Service Layer:
public interface IUserService {
IServiceRequest GetUsers(IServiceRequest req);
}
public class UserService : IUserService {
private IUserRepository repo;
public IServiceRequest GetUsers(IServiceRequest req) {
IEnumerable<User> users = null;
try {
users = repo.GetAll();
}
catch(MySqlException ex) {
req.AddError(new Error { Code = (int)ex.Number, Message = ex.Message });
}
finally {
req.EntityCollection = users;
}
return req;
}
}
public interface IServiceRequest {
IEnumerable<Object> EntityCollection { get; set; }
List<Error> Errors { get; }
void AddError(Error error);
}
public class ServiceRequest : IServiceRequest {
public IEnumerable<Object> EntityCollection { get; set; }
public virtual List<Error> Errors { get; private set; }
public ServiceRequest () { }
public void AddError(Error error) {
if(this.Errors == null) this.Errors = new List<Error>();
this.Errors.Add(error);
}
}
Like I said, it's probably something I'm doing wrong, I'm thinking in the mockService.Setup() but I'm not sure where. Help please?
From the use of service.GetUsers(req) it looks like service is suppose to populate the service request but in your setup you have it returning a service request. A result which is also not used according to your code.
You need a Callback to populate whatever parameter is given to the service in order to mock/replicate when it is invoked. Since the parameter is being created inside of the method you will use Moq's It.IsAny<> to allow the mock to accept any parameter that is passed.
var mockService = new Mock<IUserService>();
mockService.Setup(svc => svc.GetUsers(It.IsAny<IServiceRequest>()))
.Callback((IServiceRequest arg) => {
arg.EntityCollection = new List<User> { new User() };
});
This should allow the method under test to flow through it's invocation and allow you to assert the outcome.
After writing many repositories and interfaces for my data access i understood that ive been rewriting many codes over and over so i sought to understand the generic repository pattern and the unit of work. I followed the tutorial here.
After implementing the example and incorporating the needed part to my project. I faced the problem of
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code
Additional information: An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
From my research i was made to understand that i could be using two database contexts hence the error. I have this GenericRepository class and the Unit of work class where i register all my repository below
public class GenericRepository<TEntity> where TEntity : class
{
internal ApplicationDbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(ApplicationDbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
if (dbSet != null) dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
Here is the unit of work class
public class UnitOfWork : IDisposable
{
private ApplicationDbContext context = new ApplicationDbContext();
private GenericRepository<Transactions> transactionRepository;
private GenericRepository<PendingReason> penReasonRepository;
private GenericRepository<DeclineReason> decReasonRepository;
private GenericRepository<LoanStatus> loanStatusRepository;
private GenericRepository<SalesAgent> salesAgentRepository;
public GenericRepository<Transactions> TransactionRepository
{
get
{
if (this.transactionRepository == null)
{
this.transactionRepository = new GenericRepository<Transactions>(context);
}
return transactionRepository;
}
}
public GenericRepository<PendingReason> PenReasonRepository
{
get
{
if (this.penReasonRepository == null)
{
this.penReasonRepository = new GenericRepository<PendingReason>(context);
}
return penReasonRepository ;
}
}
public GenericRepository<DeclineReason> DecReasonRepository
{
get
{
if (this.decReasonRepository == null)
{
this.decReasonRepository = new GenericRepository<DeclineReason>(context);
}
return decReasonRepository;
}
}
public GenericRepository<LoanStatus> LoanStatusRepository
{
get
{
if (this.loanStatusRepository == null)
{
this.loanStatusRepository = new GenericRepository<LoanStatus>(context);
}
return loanStatusRepository;
}
}
public GenericRepository<SalesAgent> SalesAgentRepository
{
get
{
if (this.salesAgentRepository == null)
{
this.salesAgentRepository = new GenericRepository<SalesAgent>(context);
}
return salesAgentRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
In my the create action of my controller i have a point where i use the usermanager object to get the id of the current user. In that point there is a reference to the ApplicationDbContext which i think is causing the problem. However i may be wrong. Below is my controller action
[HttpPost]
public ActionResult Create(Transactions transactions)
{
using (var unit = new UnitOfWork())
{
if (ModelState.IsValid)
{
MapTransactions(new CreateTrnVM(), transactions);
unit.TransactionRepository.Insert(transactions);
unit.Save();
return RedirectToAction("Index");
}
ViewBag.DeclineReasonId = new SelectList(unit.DecReasonRepository.Get(), "DeclineReasonId", "DecReason");
ViewBag.PendingReasonsId = new SelectList(unit.PenReasonRepository.Get(), "PendingReasonId", "PenReason");
ViewBag.StatusId = new SelectList(unit.LoanStatusRepository.Get(), "StatusId", "Status");
return View(new CreateTrnVM());
}
This is the MapTransactions Method.
public void MapTransactions(CreateTrnVM model, Transactions source)
{
source.TrnDate = DateTime.Now;
ApplicationUser currentUser;
using (var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
currentUser = manager.FindById(User.Identity.GetUserId());
}
source.Agent = currentUser.SalesAgent;
}
When trying to create a Transaction, This error keeps coming out
System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code
Additional information: An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
A further research led me to this statement on this link.
In a real application you’ll have to decide if you want to mingle your
data context with IdentityDbContext. One issue to be aware of is that
the UserStore class does not play well when using the unit of work
design pattern. Specifically, the UserStore invokes SaveChanges in
nearly every method call by default, which makes it easy to
prematurely commit a unit of work. To change this behavior, change the
AutoSaveChanges flag on the UserStore.
var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
store.AutoSaveChanges = false;
This still didnt work. or maybe something else is the problem.
From various posts and research i finally got to know that the problem was that i was using a separate instance of the ApplicationDbContext as it was clashing with the one instantiated in the Unit of work class. This occured in the point where i was trying to get the User id of the current logged in user by using the UserManager class. A little research showed me this from K Scot Allen blog
In a real application you’ll have to decide if you want to mingle your
data context with IdentityDbContext. One issue to be aware of is that
the UserStore class does not play well when using the unit of work
design pattern. Specifically, the UserStore invokes SaveChanges in
nearly every method call by default, which makes it easy to
prematurely commit a unit of work. To change this behavior, change the
AutoSaveChanges flag on the UserStore.
var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
store.AutoSaveChanges = false;
The suggestion above didnt help me but it drove me to find out more about the problem and i got to this stackoverflow link which suggested that i create the UserManager class in the Unit of work class. Modifying my code above to include
private UserManager<ApplicationUser> _userManager;
public UserManager<ApplicationUser> UserManager
{
get
{
if (this._userManager == null)
{
this._userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
}
return _userManager;
}
}
I was able to get access to the UserManager class in the controller without using the ApplicationDbContext directly. I modified my controller like this
public ActionResult Create(Transactions transactions)
{
using (var unit = new UnitOfWork())
{
if (ModelState.IsValid)
{
transactions.TrnDate = DateTime.Now;
var manager = unit.UserManager;
var currentUser = manager.FindById(User.Identity.GetUserId());
transactions.Agent = currentUser.SalesAgent;
unit.TransactionRepository.Insert(transactions);
unit.Save();
return RedirectToAction("Index");
}
ViewBag.StatusId = new SelectList(unit.LoanStatusRepository.Get(), "StatusId", "Status");
return View(new CreateTrnVM());
}
Take note of this three lines
var manager = unit.UserManager;
var currentUser = manager.FindById(User.Identity.GetUserId());
transactions.Agent = currentUser.SalesAgent;
I hope it helps other people.
The problem is on this line source.Agent = currentUser.SalesAgent;
You're setting an entity SalesAgent that was retrieved by one instance of ApplicationDbContext that is different from the instance that was used to get the source.
I am working on an asp.net mvc web application. now i have created multiple repositories classes, for example i have the following abstract repository classes:-
public interface ISkillRepository : IDisposable
{//code goes here..
&
public interface IStaffRepository : IDisposable
{//code goes here
and the model Repositories:-
public class SkillRepository : ISkillRepository , IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
//code goes here
&
public class StaffRepository : IStaffRepository , IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
now inside y controller i am intializing and creating the repo as follow:-
public class SkillController : Controller
{
private ISkillRepository skillRepository;
public SkillController() : this(new SkillRepository()) {}
public SkillController(ISkillRepository repository)
{
skillRepository = repository;
}
but currently i got the following error inside my application:
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
and the problem is that i need to be passing the same context accross the repos and controllers. so can anyone adivce on this:-
how i can inside one model repo to reference another repo using the same context class. for example inside the Staff repositoryto referecne the skill repository?
how i can inside a controller class to refer multiple repos , but at the same time pass the same context object among them , so if i issue a save() it will wrap all the statements inside one transaction. for example insie my skillController to reference both the skill & staff repos using the same context object ?
Thanks
Edit
I have created the following Unit of work class:-
public class UnitOfWork : IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
private SkillRepository skillRepository;
private StaffRepository staffRepository;
private SecurityRoleRepository securityroleRepository;
public SkillRepository SkillRepository
{
get
{
if (this.skillRepository == null)
{
this.skillRepository = new SkillRepository(context);
}
return skillRepository;
}
}
public StaffRepository StaffRepository
{
get
{
if (this.staffRepository == null)
{
this.staffRepository = new StaffRepository(context);
}
return staffRepository;
}
}
public SecurityRoleRepository SecurityRoleRepository
{
get
{
if (this.staffRepository == null)
{
this.staffRepository = new SecurityRoleRepository(context);
}
return securityroleRepository;
}
}
public async Task Save()
{
await context.SaveChangesAsync();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
and then inside my repo i did the following:-
public class SecurityRoleRepository : ISecurityRoleRepository , IDisposable
{
private SkillManagementEntities context;// = new SkillManagementEntities();
public SecurityRoleRepository(SkillManagementEntities context)
{
this.context = context;
and on the controller class i will be referencing the UnitOfWork as follow:-
public class SecurityRoleController : Controller
{
private UnitOfWork unitOfWork = new UnitOfWork();
public async Task<ActionResult> Index(string filter = null, int page = 1, int pageSize = 20, string sort = "Name", string sortdir = "ASC")
{
try
{
var records = new PagedList<SecurityRole>();
ViewBag.filter = filter;
records.Content = await unitOfWork.SecurityRoleRepository.GetSecurityRoleForGrid(filter, page, pageSize, sort, sortdir).ToListAsync();
now i am facing a problem is that how i can referecne a repo from another Repo ? for example how i can reference the Skill repo inside the SecurityRole repo ?
EDIT Final
i did the following steps:-
1. i install
Install-Package Ninject.MVC5
2. then i created the following dependency class:-
public class YourDependencyResolverClass : IDependencyResolver
{
private IKernel kernel;
public YourDependencyResolverClass()
{
kernel = new StandardKernel();
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
kernel.Bind<ISkillRepository>().To<SkillRepository>();
kernel.Bind<IStaffRepository>().To<StaffRepository>();
kernel.Bind<ISecurityRoleRepository>().To<SecurityRoleRepository>();
kernel.Bind<ICustomerRepository>().To<CustomerRepository>();
kernel.Bind<ISkillVersionHistoryRepository>().To<SkillVersionHistoryRepository>();
}
}
}
3.now inside my SkillRepository class i will be referencing the StaffRepository as follow:-
public class SkillRepository : ISkillRepository , IDisposable
{
private SkillManagementEntities context ;
private IStaffRepository staffrepo = (IStaffRepository)DependencyResolver.Current.GetService(typeof(IStaffRepository));
public SkillRepository(SkillManagementEntities context)
{
this.context = context;
}
Finally inside my action method i will be calling the Uiteofwork class as follow:-
public class StaffController : Controller
{
//private SkillManagementEntities db = new SkillManagementEntities();
UnitOfWork unitofwork = new UnitOfWork();
public async Task<ActionResult> AutoComplete(string term)
{
var staff = await unitofwork.StaffRepository.GetAllActiveStaff(term).Select(a => new { label = a.SamAccUserName }).ToListAsync();
return Json(staff, JsonRequestBehavior.AllowGet);
and the unite of work class is :-
public class UnitOfWork : IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
private SkillRepository skillRepository;
private StaffRepository staffRepository;
private SecurityRoleRepository securityroleRepository;
private CustomerRepository customerRepository;
private SkillVersionHistoryRepository SVH;
public SkillRepository SkillRepository
{
get
{
if (this.skillRepository == null)
{
this.skillRepository = new SkillRepository(context);
}
return skillRepository;
}
}
public StaffRepository StaffRepository
{
get
{
if (this.staffRepository == null)
{
this.staffRepository = new StaffRepository(context);
}
return staffRepository;
}
}
public CustomerRepository CustomerRepository
{
get
{
if (this.customerRepository == null)
{
this.customerRepository = new CustomerRepository(context);
}
return customerRepository;
}
}
public SecurityRoleRepository SecurityRoleRepository
{
get
{
if (this.securityroleRepository == null)
{
this.securityroleRepository = new SecurityRoleRepository(context);
}
return securityroleRepository;
}
}
public SkillVersionHistoryRepository SkillVersionHistoryRepository
{
get
{
if (this.SVH == null)
{
this.SVH = new SkillVersionHistoryRepository(context);
}
return SVH;
}
}
public async Task Save()
{
await context.SaveChangesAsync();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
So can you adivce if my approach of using unitefwork and DI will guarantee that all my statements will be warped inside a single DB transaction ? thnaks?
We handle this by sharing a context using a singleton that is scoped to the request using HttpContext:
public MyContext GetContext()
{
if (System.Web.HttpContext.Current.Items["MyScopedContext"] == null)
{
System.Web.HttpContext.Current.Items["MyScopedContext"] = new MyContext();
}
return (MyContext)System.Web.HttpContext.Current.Items["MyScopedContext"];
}
The context object (repository) itself essentially houses a Unit of Work. The code I added above just gives you a way to share a single repository across all code running within a request. If your repository classes are defined in the scope of a web application, you can just replace your direct instantiation of SkillManagementEntities() with a call to a GetContext() method.
On the other hand if your repositories are defined in a layer shared by heterogeneous applications, you may need to get your context from a factory object that you can inject as needed. Either way, creating a new context object per repository is what's causing your issue.
Not an answer: this "use DI" suggestion answers a bit different question - OP is looking for "unit-of-work" pattern - while basic case (lifetime of unit of work matches lifetime of request/controller) can easily be solved with any DI framework, managing multiple units of work or units of work with longer lifetime is much harder and dedicated "unit of work factory" (sample usage) is likely the solution.
Usually when you go that far with interfaces/repositories and constructor dependency injection you have some Dependency Injection framework. There is a good chance that one you are using already provides "per HTTP request" resolution or allows to easily add one.
I.e. if you using Unity there is PerRequestLifetime lifetime manager that makes all .Resolve calls for the same interface/object to return the same instance for given request. See more info in DI with Unity MSDN article.
Approximate sample:
container.RegisterType<ISkillRepository, SkillRepository>();
container.RegisterType<IOtherRepository, OtherRepository>();
container.RegisterType<TheContext, TheContext>(new PerRequestLifetime());
With such registration and assuming you've configured ASP.Net MVC to use Unity to resolve types when controller is created it will get necessary dependencies (new instances as registered with default lifetime), but both will share the same context (assuming each depends on TheContext class either via constructor or property injection).
I am testing the create class in Visual Studio 2012
My controller class is:
public ActionResult Create()
{
return View();
}
//
// POST: /Member/Create
[HttpPost]
public ActionResult Create(Member member)
{
if (ModelState.IsValid)
{
db.Members.Add(member);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(member);
}
And test class is:
[TestClass]
public class MemberTest
{
[TestMethod]
public void Create(Member mem)
{
mem.MemID = 123;
mem.MemName = "sruthy";
/// dont know what is writing.
}
}
SampleDataContext.cs
public class SampleDataContext:DbContext
{
public DbSet<Member> Members { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
I am stuck in test case please help me.
First - create an abstraction for your data access code (mocking DbContext is not very convenient thing):
public interface IMemberRepository
{
void Add(Member member);
}
and make your controller depend on it
public MemberController(IMemberRepository repository)
{
this.repository = repository;
}
This will allow mock data access code easily. Next - write tests which verify controller behavior (I use NUnit and Moq here):
private MemberController controller;
private Mock<IMemberRepository> repositoryMock;
private Member member;
[SetUp]
public void Setup()
{
repositoryMock = new Mock<IMemberRepository>();
controller = new MemberController(repositoryMock.Object);
member = new Member { MemID = 123, MemName = "sruthy" };
}
[Test]
public void ShouldCreateMemberWhenItIsValid()
{
var result = (RedirectToRouteResult)controller.Create(member);
Assert.That(result.RouteValues["action"], Is.EqualTo("Index"));
repositoryMock.Verify(r => r.Add(member));
}
[Test]
public void ShouldNotCreateMemberWhenItIsNotValid()
{
controller.ModelState.AddModelError("MemName", "Something wrong");
var result = (ViewResult)controller.Create(member);
Assert.That(result.ViewName, Is.Empty);
}
And write implementation:
[HttpPost]
public ActionResult Create(Member member)
{
if (ModelState.IsValid)
{
repository.Add(member);
return RedirectToAction("Index");
}
return View(member);
}
What I understood in unit testing is : "test only what your method is doing" So I think you have to test your method is doing well:
ModelState.IsValid
db.Members.Add(member)
db.SaveChanges()
But not the good behavior of ModelState or DbContext. These are tested in their own unit tests. You have to assert only the call is done.
To perform this kind of test you have to use the Dependency injection pattern and replace the real DbContext by mocks. These mocks are just asserting the call is well executed without involving the real dbContext.
I'm not a specialist in unit testing but I think you have to think all your architecture in order to decouple your objects. This allow you to replace real objects by mocks.
I'm new to Ninject so I'm sure that it's something I'm doing wrong, I'm just not sure what. I'm using Ninject and Ninject.MVC3 in my MVC3 web application. Here's an example of what I'm trying to do.
I'm using the Repository pattern:
public interface IRepository<T>
{
T Get(object id);
IList<T> GetAll();
void Add(T value);
void Update(T value);
void Delete(T value);
}
For a concrete type:
public Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public Customer()
{
}
}
Now I have 2 separate repositories, a cached version that needs injection to the database repository:
public CachedCustomerRepository : IRepository<Customer>
{
private IRepository<Customer> _repository;
public Customer Get(object id)
{
Customer cust = new Customer();
IList<Customer> custs = GetAll();
if (custs != null && custs.Count > 0)
cust = custs.FirstOrDefault(c => c.Id == int.Parse(id.ToString()));
return cust;
}
public IList<Customer> GetAll()
{
IList<Customer> custs = HttpRuntime.Cache["Customers"] as IList<Customer>;
if (custs == null)
{
custs = _repository.GetAll();
if (custs != null && custs.Count() > 0)
{
double timeout = 600000d;
HttpRuntime.Cache.Insert("Customers", custs, null, DateTime.UtcNow.AddMilliseconds(timeout), System.Web.Caching.Cache.NoSlidingExpiration);
}
else
{
throw new NullReferenceException();
}
}
return custs;
}
public void Add(Customer value)
{
throw new NotImplementedException();
}
public void Update(Customer value)
{
throw new NotImplementedException();
}
public void Delete(Customer value)
{
throw new NotImplementedException();
}
public CachedCustomerRepository()
{
}
[Inject]
public CachedCustomerRepository(IRepository<Customer> repository)
{
_repository = repository;
}
}
public class CustomerRepository : IRepository<Customer>
{
public Customer Get(object id)
{
Customer cust = new Customer();
IList<Customer> custs = GetAll();
if (custs != null && custs.Count > 0)
cust = custs.FirstOrDefault(c => c.Id == int.Parse(id.ToString()));
return cust;
}
public IList<Customer> GetAll()
{
//Customer retrieval code
}
public void Add(Customer value)
{
throw new NotImplementedException();
}
public void Update(Customer value)
{
throw new NotImplementedException();
}
public void Delete(Customer value)
{
throw new NotImplementedException();
}
public CachedCustomerRepository()
{
}
}
I set up a NinjectModule like this:
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IRepository<Customer>>().To<CustomerRepository>();
}
}
and I modified the NinjectMVC3.cs in the AppStart folder to get the module when creating the kernel:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel(new ServiceModule());
RegisterServices(kernel);
return kernel;
}
In my controller I am using this:
public ViewResult Index()
{
IRepository<Customer> custRepo = new CachedCustomerRepository();
return View(custRepo.GetAll());
}
It blows up on the line _repository.GetAll() in my CachedCustomerRepository.
I've set a breakpoint to make sure that the CreateKernel() is executing and getting the bindings, which it is. I'm just not sure why the injection isn't happening. One other side note, I don't know if it's important or not, the IRepository, the Repositories and the concrete type are in a separate class library and is referenced in the mvc3 web app. Both the web app and the class library have a reference to Ninject and the web app also has a reference to Ninject.MVC3. The binding and kernel creation is all taking place in the Web App.
First, you're calling the wrong constructor in your controller. This parameterless constructor doesn't call anything else and that's why you're getting the null exception. Second, you want to refactor your controller so that there are no direct dependencies.
You'd want to do something like the following:
public class SomeController
{
private readonly IRepository<Customer> repo;
public SomeController(IRepository<Customer> repo)
{
this.repo = repo;
}
public ViewResult Index()
{
return View(this.repo.GetAll());
}
}
This way, Ninject resolves the dependency for you! Ninject's kernel will be asked to create a controller with IRepository<Customer> by MVC. Since Ninject has this "binding", it'll try to instantiate the CustomerRepository for you.
Also, why are you creating a "CachedRepository"? I really, really think you're prematurely optimizing this. Honestly, you only need the one CustomerRepository and you'd wire that up within the Ninject module.
Have you made the class in Global.asax inherit NinjectHttpApplication?
Make sure you're calling DependencyResolver.SetResolver(CreateKernel()); in order to tell MVC which resolver you're going to use. You might be calling it but I didn't see it in your post - otherwise your code looks fine.
To get the full benefit of using an IOC you should refactor the CachedCustomerRepository dependency from you controller class. You will need to add a new binding to the your Ninject module. This binding will need to use the context to determine if it is binding the 'IRepository' to a CachedCustomerRepository instance or to the MVC Controller instance. Once you have that factored out, then Ninject will create and manage the lifetimes of both objects.
The problem is that when you create the CachedCustomerRepository in your action method, you're just instantiating it yourself and you're not getting Ninject to instantiate it for you and subsequently inject it's dependencies.
What you should do is use constructor injection for the controller.
E.g.
public class MyController : Controller
{
public IRepository<Customer> CustomerRepo { get; protected set; }
public MyController(IRepository<Customer> customerRepo)
{
CustomerRepo = customerRepo;
}
public ViewResult Index()
{
return View(CustomerRepo.GetAll());
}
}
Your scenario is slightly confusing though, because you are injecting a IRepository<Customer> into a IRepository<Customer> that needs to be injected into MyController.