I have Added Unit Testing in Existing MVC project and also added references
when i create object of controller
it throws an Exception due to DBContext context object i created in MVC but I need to do Dependency Injection and mocking so that it will not check for it.
please how can i make interface of db to do dependency injection.
code in mvc
public class TestingController : Controller
{
//
// GET: /Testing/
ApplicationDbContext db = new ApplicationDbContext();
Random rnd = new Random();
[Authorize]
public ActionResult Index()
{
string uName = User.Identity.GetUserName();
QuestionsViewModel vm = new QuestionsViewModel();
List<AddQuestion> adlist = new List<AddQuestion>();
List<QuestionsViewModel> qlist = new List<QuestionsViewModel>();
List<int> rn = new List<int>();
List<int> rn2 = new List<int>();
List<int> rn3 = new List<int>();
AddQuestion adq = new AddQuestion();
var Sessionid = System.Guid.NewGuid();
vm.sessionid = Sessionid.ToString();
Session["ApplicantSession"] = Sessionid.ToString();
ViewBag.StartTime = Session.Timeout;
List<List<int>> threecompQids = new List<List<int>>();
List<int> c1question = db.AddQuestions.Where(x => x.ComplexityLevel == 1)
.Select(y => y.AddQuestionID).ToList();
List<int> c2question = db.AddQuestions.Where(x => x.ComplexityLevel == 2)
.Select(y => y.AddQuestionID).ToList();
List<int> c3question = db.AddQuestions.Where(x => x.ComplexityLevel == 3)
.Select(y => y.AddQuestionID).ToList();
for (int i = 0; i < 5; i++)
{
int r = rnd.Next(c1question.Min(), c1question.Max() + 1);
while (!(c1question.Any(w => w.Equals(r)) && !rn.Any(w => w == r)))
{
r = rnd.Next(c1question.Min(), c1question.Max() + 1);
}
rn.Add(r);
r = rnd.Next(c2question.Min(), c2question.Max() + 1);
while (!(c2question.Any(w => w.Equals(r)) && !rn2.Any(w => w == r)))
{
r = rnd.Next(c2question.Min(), c2question.Max() + 1);
}
rn2.Add(r);
r = rnd.Next(c3question.Min(), c3question.Max() + 1);
while (!(c3question.Any(w => w.Equals(r)) && !rn3.Any(w => w == r)))
{
r = rnd.Next(c3question.Min(), c3question.Max() + 1);
}
rn3.Add(r);
}
var fstquestion = rn[0];
threecompQids.Add(rn);
threecompQids.Add(rn2);
threecompQids.Add(rn3);
vm.ComplexLevQidsLists = threecompQids;
adq = db.AddQuestions.Find(fstquestion);
List<Option> opt = db.Options.Where(op => op.AddQuestionID == adq.AddQuestionID).ToList();
vm.Questions = adq;
vm.Options = opt;
vm.UserName = uName;
return View(vm);
}
}
where as in test project i only created object of testcontroller
It seems like you didn't mock data access component your controller depends on, right? If this is the case and you are using actual implementation in your unit test, most likely your connection string defined in Test project is missing or differs from the connection string defined in MVC project.
Also keep in mind that if you do not mock your controller's dependencies, your unit test is technically cannot be considered as "unit" — it's more like an integration or scenario test.
You should either abstract the ApplicationDbContext using an interface like IAppDbContext or provide the connection string to the testing project too. In the latter case your test will stop being unit test though.
public class MyController: Controller
{
IAppDbContext _context;
pulbic MyController(IAppDbContext context)
{
_context = context; // Now you can use the interface to perform your data access operations
}
....
}
And now you will be able to inject mock implementations of IAppDbContext in your unit tests.
You should do some research on Dependency Inversion and Mocking.
Related
I have ASP.NET Core 2.2 application using EF Core. In startup.cs i am setting CommandTimeout to 60 seconds
services.AddDbContext<CrowdReason.WMP.Data.Entities.WMPContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
sqlServerOptions => sqlServerOptions.CommandTimeout(60)));
Then i am executing the stored proc using the following code. Please note the values of t1, t2 and t3 in comments
public static async Task<int?> prcDoWork(this WMPContext dbContext, int id, int userID)
{
var t1 = dbContext.Database.GetCommandTimeout();
// t1 is 60. Same as what i set in startup.cs
using (var connection = dbContext.Database.GetDbConnection())
{
var t2 = connection.ConnectionTimeout;
//t2 is 15
using (var cmd = connection.CreateCommand())
{
var p1 = new SqlParameter("#ID", SqlDbType.Int)
{
Value = id
};
var p2 = new SqlParameter("#UserID", SqlDbType.Int)
{
Value = userID
};
cmd.CommandText = "dbo.prcDoWork";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(p1);
cmd.Parameters.Add(p2);
var t3 = cmd.CommandTimeout;
//t3 is 30
await dbContext.Database.OpenConnectionAsync().ConfigureAwait(false);
var result = await cmd.ExecuteScalarAsync().ConfigureAwait(false);
if (result != null)
{
return Convert.ToInt32(result);
}
return null;
}
}
}
I understand that ConnectionTimeout is different from CommandTimeout.
However issue is when i create command using connection.CreateCommand() its not automatically getting the timeout from DBContext
EF Core works on top of the underlying System.Data implementation (in your case System.Data.SqlClient) and uses it to perform its DB operations. All settings you make will only reflect the way EF uses this underlying implementation.
When you use the GetDbConnection method you get a reference to an SqlConnection class from the System.Data.SqlClient assembly that knows nothing about EF and its settings and cannot be expected to honor the RelationalOptionsExtension.CommandTimeout from the Microsoft.EntityFrameworkCore.Relational assembly.
To have EF settings respected you should use the RelationalDatabaseFacadeExtensions.ExecuteSqlCommandAsync method.
I'm refactoring some previously written MVC and Entity Framework code. The way the initial code was written they called a DAL.GetGroupDetail(int groupId) method. In that method it created a ViewModel and populated several properties. Some of those properties are Lists for things like CostCenters, Cities, Groups. I want to break those calls out into their own methods so that they can be re-used in other controllers.
My question is that doing that I'm creating new Contexts using the Using statement. My understanding is that would create multiple connections to the database and thus would slow down the site if multiple users were using it at the same time?
Example, currently this is the basic code:
public ClockGroupViewModel GetClockGroupDetail(int groupId)
{
GroupViewModel cgdv = new GroupViewModel();
using (var ctx = new VTContext())
{
bio_group group = ctx.bio_group.Where(x => x.group_id == groupId).FirstOrDefault();
cgdv.GroupId = group.group_id;
cgdv.GroupName = group.group_name;
cgdv.Cities = ctx.bio_city.ToList();
var clocks = from c in ctx.bio_clock.Where(x => x.group_id == groupId)
select new ClockViewModel
{
ClockID = c.rdr_id.ToString(),
ClockDescription = c.clock_desc,
};
cgdv.ClockList = clocks.ToList();
cgdv.CostCtrList = (from g in ctx.bio_clock_group
from cgc in ctx.bio_clock_group_costctr
where cgc.group_id == g.group_id && g.group_id == groupId
select cgc.cost_ctr).ToList();
}
This how I'm thinking of changing it:
public ClockGroupViewModel GetClockGroupDetail(int groupId)
{
GroupViewModel cgdv = new GroupViewModel();
using (var ctx = new VTContext())
{
bio_group group = ctx.bio_group.Where(x => x.group_id == groupId).FirstOrDefault();
cgdv.GroupId = group.group_id;
cgdv.GroupName = group.group_name;
cgdv.Cities = GetCityList();
cgdv.ClockList = GetClockGroupClockList(group.group_id);
cgdv.CostCtrList = GetGroupCostCenter(group.group_id);
}
}
public List<bio_clock_city> GetCityList()
{
using (var ctx = new VTContext())
{
return ctx.bio_city.ToList();
}
}
public List<ClockViewModel> GetClockGroupClockList(int groupId)
{
using (var ctx = new VTContext())
{
var data = (from c in ctx.bio_clock.Where(x => x.group_id == groupId)
select new ClockViewModel
{
ClockID = c.rdr_id.ToString(),
ClockDescription = c.clock_desc,
}).ToList();
return data;
}
}
public List<string> GetGroupCostCenter(int groupId)
{
using (var ctx = new VTContext())
{
var data = (from g in ctx.bio_clock_group
from cgc in ctx.bio_clock_group_costctr
where cgc.group_id == g.group_id && g.group_id == groupId
select cgc.cost_ctr).ToList();
return data;
}
}
I'm switching over from structure map to Autofac. I've use a caching pattern from Scott Millett's book ASP.net Design Patterns which implements an interface for both Cache and the Repository and switches in the appropriate object depending on the constructor parameter name
The interface looks like this
public interface ISchemeRepository
{
List<Scheme> GetSchemes();
}
The cache object looks like this
public class SchemeRepository : BaseRepository, ISchemeRepository
{
/***************************************************************
* Properties
***************************************************************/
private readonly ISchemeRepository schemeRepository;
/***************************************************************
* Constructors
***************************************************************/
public SchemeRepository()
: this(ObjectFactory.GetInstance<ISchemeRepository>(), ObjectFactory.GetInstance<IConfigurationSetting>())
{
}
public SchemeRepository(ISchemeRepository realSchemeRepository, IConfigurationSetting configurationSetting)
{
schemeRepository = realSchemeRepository;
this.configurationSetting = configurationSetting;
}
/**************************************************************
* Methods
***************************************************************/
public List<Scheme> GetSchemes()
{
string key = Prefix + "Schemes";
if (!MemoryCache.Default.Contains(key))
{
MemoryCache.Default.Add(key, schemeRepository.GetSchemes(), new CacheItemPolicy());
}
return (List<Scheme>)MemoryCache.Default.Get(key);
}
}
The repository looks like this
public class SchemeRepository : BaseLocalRepository, ISchemeRepository
{
/***************************************************************
* Properties
***************************************************************/
private readonly IConnectionSetting connectionSetting;
/***************************************************************
* Constructors
***************************************************************/
public SchemeRepository()
: this(ObjectFactory.GetInstance<IConnectionSetting>())
{
}
public SchemeRepository(IConnectionSetting connectionSetting)
{
this.connectionSetting = connectionSetting;
}
/**************************************************************
* Methods
***************************************************************/
public List<Scheme> GetSchemes()
{
var response = new List<Scheme>();
var conn = new SqlConnection(connectionSetting.CQBConnectionString);
var command = new SqlCommand("proc_GetSchemes", conn) { CommandType = CommandType.StoredProcedure };
conn.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
response.Add(
new Scheme
{
SchemeId = reader["Scheme_Id"].ToString().Trim(),
GuaranteeText = reader["Guarantee_Text"].ToString().Trim()
}
);
}
conn.Close();
return response;
}
}
The structure map call is below
InstanceOf<Repository.Local.Contract.IProviderRepository>().Is.OfConcreteType<Repository.Local.Core.ProviderRepository>().WithName("RealProviderRepository");
ForRequestedType<Repository.Local.Contract.IProviderRepository>().TheDefault.Is.OfConcreteType<Repository.Local.Cache.ProviderRepository>().CtorDependency<Repository.Local.Contract.IProviderRepository>().Is(x => x.TheInstanceNamed("RealProviderRepository"));
Structure map looks at the constructor and if it contains a parameter called "realSchemeRepository" then it implements the object that connect to the database, if not it implements the cache object that checks the cache and calls the database if nothing is in the cache and populates the cache.
How do I do this in Autofac? Is there a better way of doing this in Autofac?
I believe what you're asking how to do is set up a decorator between your two repository classes. I'm gonna pretend the two class names are CacheSchemeRepository and RealSchemeRepository because naming them exactly the same is confusing and terrible. Anyways...
builder.Register(c => new RealSchemeRepository(c.Resolve<IConnectionSetting>())
.Named<ISchemeRepository>("real");
builder.RegisterDecorator<ISchemeRepository>(
(c, inner) => new CacheSchemeRepository(inner, c.Resolve<IConfigurationSetting>()),
"real");
I'm new to both ADO .NET and MVC, and I am trying to do something simple where I am editting a "DailyReport", which is basically representing a work-report.
Here's my relevant controller pattern:
//
// GET: /DailyReport/Edit/5
public ActionResult Edit(int id, int weeklyReportID, int day)
{
WeeklyReport weeklyReport = (
from WeeklyReport wr in db.WeeklyReports
where wr.Id == weeklyReportID select wr)
.FirstOrDefault();
ViewBag.Week = weeklyReport.Week;
ViewBag.Day = day;
return View();
}
//
// POST: /DailyReport/Edit/5
[HttpPost]
public ActionResult Edit(DailyReport dailyReport, int weeklyReportID, int day)
{
if (ModelState.IsValid)
{
db.SaveChanges();
if (dailyReport == null)
{
dailyReport = new DailyReport();
dailyReport.StartTime = new TimeSpan(7, 0, 0);
dailyReport.EndTime = new TimeSpan(7 + 8, 0, 0);
dailyReport.Day = day;
db.DailyReports.AddObject(dailyReport);
db.SaveChanges();
}
WeeklyReport weeklyReport = (
from WeeklyReport wr in db.WeeklyReports
where wr.Id == weeklyReportID select wr)
.FirstOrDefault();
if (!weeklyReport.DailyReport.Any(dr => dr.Id == dailyReport.Id))
{
weeklyReport.DailyReport.Add(dailyReport);
}
dailyReport.WeeklyReport = weeklyReport;
db.SaveChanges();
return RedirectToAction("Edit",
"WeeklyReport",
new {
id = weeklyReportID,
week = weeklyReport.Week,
year = weeklyReport.Year
});
}
return View(dailyReport);
}
When I am editting the datetime value, it doesn't get saved. In the HttpPost section when I debug it, the object is indeed changed to reflect these changes, but calling db.SaveChanges() doesn't commit it to the database.
Edit "db" in this case is my ADO .NET context, declared in the following way:
ActivesEntities db = new ActivesEntities();
ActivesEntities has this declaration:
public partial class ActivesEntities : ObjectContext { ... }
First of all, I would recommend you to not call the db.SaveChanges until you really need to save an Entity object in the middle of the series of Transactional Steps..
Because Entity Framework support saving all the EntityContext object in a single shot !
And I think you may try changing the code like this,
[HttpPost]
public ActionResult Edit(DailyReport dailyReport, int weeklyReportID, int day)
{
if (ModelState.IsValid)
{
if (dailyReport == null)
{
dailyReport = new DailyReport();
dailyReport.StartTime = new TimeSpan(7, 0, 0);
dailyReport.EndTime = new TimeSpan(7 + 8, 0, 0);
dailyReport.Day = day;
db.DailyReports.AddObject(dailyReport);
}
WeeklyReport weeklyReport = (from WeeklyReport wr in db.WeeklyReports where wr.Id == weeklyReportID select wr).SingleOrDefault();
if (!weeklyReport.DailyReport.Any(dr => dr.Id == dailyReport.Id))
{
weeklyReport.DailyReport.Add(dailyReport);
}
dailyReport.WeeklyReport = weeklyReport;
db.SaveChanges();
return RedirectToAction("Edit", "WeeklyReport", new { id = weeklyReportID, week = weeklyReport.Week, year = weeklyReport.Year });
}
I think using if you are Updating the entity object then you need to call SingleOrDefault and not FirstOrDefault. I do it like this on Linq2Sql..
you are using entity framework right? it's a bit different from ADO.NET (it uses it but those are not 100% same thing), we should add the tag EF to the question.
said so, why do you call db.SaveChanges twice? I would not call it at the top of your Edit method.
also, as I see in some EF examples, you can use Add and not AddObject.
check this one:
How to: Add, Modify, and Delete Objects
last thing, your StartTime and EndTime properties of the object are of type TimeSpan and not datetime?
I have almost exactly the same scenario described by Nathon Taylor in ASP.NET MVC - Sharing Session State Between Controllers. The problem is that if I save the path to the images inside a Session variable List<string> it is not being defined back in the ItemController so all the paths are being lost... Here's my setup:
Inside ImageController I have the Upload() action method:
public ActionResult Upload()
{
var newFile = System.Web.HttpContext.Current.Request.Files["Filedata"];
string guid = Guid.NewGuid() + newFile.FileName;
string itemImagesFolder = Server.MapPath(Url.Content("~/Content/ItemImages/"));
string fileName = itemImagesFolder + "originals/" + guid;
newFile.SaveAs(fileName);
var resizePath = itemImagesFolder + "temp/";
string finalPath;
foreach (var dim in _dimensions)
{
var resizedPath = _imageService.ResizeImage(fileName, resizePath, dim.Width + (dim.Width * 10/100), guid);
var bytes = _imageService.CropImage(resizedPath, dim.Width, dim.Height, 0, 0);
finalPath = itemImagesFolder + dim.Title + "/" + guid;
_imageService.SaveImage(bytes, finalPath);
}
AddToSession(guid);
var returnPath = Url.Content("~/Content/ItemImages/150x150/" + guid);
return Content(returnPath);
}
private void AddToSession(string fileName)
{
if(Session[SessionKeys.Images] == null)
{
var imageList = new List<string>();
Session[SessionKeys.Images] = imageList;
}
((List<string>)Session[SessionKeys.Images]).Add(fileName);
}
Then inside my ItemController I have the New() action method which has the following code:
List<string> imageNames;
var images = new List<Image>();
if (Session[SessionKeys.Images] != null) //always returns false
{
imageNames = Session[SessionKeys.Images] as List<string>;
int rank = 1;
foreach (var name in imageNames)
{
var img = new Image {Name = name, Rank = rank};
images.Add(img);
rank++;
}
}
Ok so why is this happening and how do I solve it?
Also, I was thinking of whether I could move the ActionMethod that takes care of the upload of the images into the ItemController and store the image paths inside a List property on the ItemController itself, would that actually work? Note though, that images are being uploaded and taken care of via an AJAX request. Then when the user submits the item entry form, all the data about the Item along with the images should be saved to the database...
Update:
I've updated the code. Also I think I should add that I'm using StructureMap as my controller factorory. Could it be a scoping issue? What is the default scope that is usually used by StructureMap?
public class StructureMapDependencyResolver : IDependencyResolver
{
public StructureMapDependencyResolver(IContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
if (serviceType.IsAbstract || serviceType.IsInterface)
{
return _container.TryGetInstance(serviceType);
}
else
{
return _container.GetInstance(serviceType);
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances<object>()
.Where(s => s.GetType() == serviceType);
}
private readonly IContainer _container;
}
And inside my Global.asax file:
private static IContainer ConfigureStructureMap()
{
ObjectFactory.Configure(x =>
{
x.For<IDatabaseFactory>().Use<EfDatabaseFactory>();
x.For<IUnitOfWork>().Use<UnitOfWork>();
x.For<IGenericMethodsRepository>().Use<GenericMethodsRepository>();
x.For<IUserService>().Use<UsersManager>();
x.For<IBiddingService>().Use<BiddingService>();
x.For<ISearchService>().Use<SearchService>();
x.For<IFaqService>().Use<FaqService>();
x.For<IItemsService>().Use<ItemsService>();
x.For<IMessagingService>().Use<MessagingService>();
x.For<IStaticQueriesService>().Use<StaticQueriesService>();
x.For < IImagesService<Image>>().Use<ImagesService>();
x.For<ICommentingService>().Use<CommentingService>();
x.For<ICategoryService>().Use<CategoryService>();
x.For<IHelper>().Use<Helper>();
x.For<HttpContext>().HttpContextScoped().Use(HttpContext.Current);
x.For(typeof(Validator<>)).Use(typeof(NullValidator<>));
x.For<Validator<Rating>>().Use<RatingValidator>();
x.For<Validator<TopLevelCategory>>().Use<TopLevelCategoryValidator>();
});
Func<Type, IValidator> validatorFactory = type =>
{
var valType = typeof(Validator<>).MakeGenericType(type);
return (IValidator)ObjectFactory.GetInstance(valType);
};
ObjectFactory.Configure(x => x.For<IValidationProvider>().Use(() => new ValidationProvider(validatorFactory)));
return ObjectFactory.Container;
}
Any thoughts?
I just added this to Global.asax.cs
protected void Session_Start()
{
}
It seems that this fixed the issue. I set a breakpoint that gets hit only once per session (as expected).
One possible reason for this is that the application domain restarts between the first and the second actions and because session is stored in memory it will be lost. This could happen if you recompile the application between the two. Try putting a breakpoints in the Application_Start and Session_Start callbacks in Global.asax and see if they are called twice.
Are you ever using it other than accessing HttpContext.Current directly in your code? In other words, are there any places where you're injecting the HttpContext for the sake of mocking in unit tests?
If you're only accessing it directly in your methods, then there's no reason to have the entry x.For<HttpContext>().HttpContextScoped().Use(HttpContext.Current); in you application startup. I wonder if it would start working if you removed it.