I'm using Moq with EF6.
In the following code, I create a mock for a 3 DbContext objects and a config manager, all of which are passed to the constructor for HomeController .
Mock<BAMContext> bamDbContext = new Mock<BAMContext>();
Mock<ESBContext> esbDbContext = new Mock<ESBContext>();
Mock<UserPrefsContext> userPrefsDbContext = MockUserPrefsContext.GetContext(interchangeIds);
var controllerContext = MockWebContext.AuthenticatedContext(adminUsers.First(), true);
Mock<IConfigurationManager> configurationManager = new Mock<IConfigurationManager>();
configurationManager.Setup(cm => cm.GetAppSetting("AdminUsers")).Returns(#"BizTalkBuild01\BizTalkAdmin;lgss\iwhite;");
HomeController controller = new HomeController(bamDbContext.Object, esbDbContext.Object, userPrefsDbContext.Object, configurationManager.Object);
controller.EnsureAdminUsersHaveDbRecs();
The EnsureAdminUserHaveDbRecs method will insert the required recs. It also sets a public property UserPrefsContext so that I reference this back in the unit test for the asserts. The inserts into the mock db context seem to work ok but if I add the following loop then the debugger does not step in:
foreach (var rec in controller.UserPrefsContext.UserRecs.ToList())
{
Debug.WriteLine(rec.AdLogonId);
}
However, if I enter ? controller.UserPrefsContext.UserRecs.Count() in the immediate window it gives a result of 3. I'm also able to print the data with e.g. ? controller.UserPrefsContext.UserRecs.First().AdLogonId
Can anyone please explain why I can't iterate over these 3 recs?
Related
I am setting up my seed methods in my migration's configuration class.
I have added a reference to the following name spaces
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
and wrote up the following method that gets called from the Seed method
private void SeedMembership(MyDbContext context)
{
var user = new ApplicationUser() { UserName = "demo"};
UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var result = UserManager.Create(user,"demo");
}
The idea was to have this aoto create a user with username=demo and password=demo
but I cant compile getting the following error:
using the generic type 'Microsoft.AspNet.Identity.UserManager<TUser>' requires 1 type argument
I am a bit stuck as to why.
Thanks!
You seem to have a typo:
var result = UserManager.Create(user,"demo");
You should use userManager, note the lower-case u.
So I have a Testclass using MSTest and every test works great if I run them one and one, however if I select 2 tests, namely can_register and cannot_Register_existing_username then the second fails (cannot_register_existing_username).
I have let my testclass inherit from an abstract class that looks like this:
public abstract class RollbackCapabilities
{
private TransactionScope _transactionScope;
[TestInitialize]
public virtual void TestInitialize()
{
_transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions { Timeout = new TimeSpan(0, 10, 0) });
}
[TestCleanup]
public virtual void TestCleanup()
{
Transaction.Current.Rollback();
_transactionScope.Dispose();
}
}
If I comment this file out then it works (but now the data remains in the test-db which I don't want).
With this file above active the second test fails, the tests look like this
[TestMethod]
public void Can_Register()
{
//Arrange
AccountController ac = ControllerFactory.CreateAccountController();
RegisterModel model = new RegisterModel();
model.UserName = "TestUser";
model.Password= "TestPassword";
model.ConfirmPassword = "TestPassword";
//Act
ActionResult result = ac.Register(model);
//Assert
Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
Assert.AreEqual("Home", ((RedirectToRouteResult)result).RouteValues["controller"]);
Assert.AreEqual("Index", ((RedirectToRouteResult)result).RouteValues["action"]);
}
[TestMethod]
public void Cannot_Register_Existing_Username()
{
//Arrange
AccountController ac = ControllerFactory.CreateAccountController();
RegisterModel model = new RegisterModel();
model.UserName = "TestUser";
model.Password = "TestPassword";
model.ConfirmPassword = "TestPassword";
ac.Register(model);
RegisterModel model2 = new RegisterModel();
model2.UserName = "TestUser";
model2.Password = "OtherTestPassword";
model2.ConfirmPassword = "OtherTestPassword";
//Act
ActionResult result = ac.Register(model2);
//Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
Assert.AreEqual("", ((ViewResult)result).ViewName);
Assert.AreEqual(model2, ((ViewResult)result).ViewData.Model);
}
and finally the error i get is as follows:
Test method
Viducate.UnitTests.UserHandling.RegisterTests.Cannot_Register_Existing_Username
threw exception: System.Data.EntityCommandExecutionException: An
error occurred while executing the command definition. See the inner
exception for details. ---> System.Data.SqlClient.SqlException:
Invalid object name 'dbo.Users'.
Thats my problem, not big but very annoying and as mentioned if I run the tests one and one it works, it also works but leaves data in the db if I comment out my RollbackCapabilities class
Okay so I found out that my error was that I had created the database (but not tables) by hand because create database is not supported in multi-transaction.
however creating an empty database means that EF assumes there is tables already and that is why it failed with dont know what dbo.users are.
So what I did was created the tables as well and now it works. However this means I can never run this on a new development machine without first creating the tables and database. so annoying.
I think I will set up another test class that does not inherit my abstract rollback class and hade that create the tables permanently... should solve the problem as long as that runs first.
I have the following piece of code
private void DoAddPropertyType()
{
var ctx = Globals.DbContext;
var propType = new PropertyType()
{
ID = Guid.NewGuid(),
Name = "NewType",
Description = "New Property Type",
ModifiedDate = DateTime.Now
};
ctx.AddToPropertyTypes(propType);
PropertyTypes.Add(propType);
}
Globals.DbContext provides a static reference to the objectcontext initiated on startup. For some reason the ctx.AddToPropertyTypes(propType); bit does not add the entity to the context. If I breakpoint after that line and browse the ctx.PropertyTypes entity set it is not there. Any ideas?
EDIT 1:
If I add a ctx.SaveChanges() after the ctx.AddToPropertyTypes(propType) and step the actual adding appears to happen only once SaveChanges execute. This however does not suit my requirements as I want to first validate objects prior to saving and wanted to iterate through the entities in the entity set. Does any one know of an alternative approach?
So that is the point of your issue. ctx.PropertyTypes is not a real collection - it is entrance to the database and your "browsing" actually executes query to the database where your new object was not yet stored. If you want to find a new object added to the context without saving it first you must search the object inside the ObjectStateManager:
var entity = ctx.ObjectStateManager
.GetObjectStateEntries(EntityState.Added)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<PropertyType>()
.SingleOrDefault(p => p.ID == ...);
I am setting up a repository with Entity Framework 4, and I can't get the ObjectSet.AddObject() method working. Here is the code I am using--to keep things simple, I copied it out of the repository into my unit test method:
/* m_FilePath value is passed in by test initializer. */
// Configure a SQL CE connection string
var sqlCompactConnectionString = string.Format("Data Source={0}", m_FilePath);
// Create an Entity Connection String Builder
var builder = new EntityConnectionStringBuilder();
builder.Metadata = string.Format("res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl", "Model.Notes");
builder.Provider = "System.Data.SqlServerCe.4.0";
builder.ProviderConnectionString = sqlCompactConnectionString;
var edmConnectionString = builder.ToString();
// Create object context and object set
var context = new NotesContainer(edmConnectionString);
var objectSet = context.CreateObjectSet<Note>();
// Add a note
var entity = new Note();
objectSet.AddObject(entity);
// Build assertion
var notes = objectSet.AsEnumerable();
var count = notes.Count();
Assert.AreEqual(1, count);
The count that is returned is zero--the object set is empty, so the assertion fails. When I step through the code, the object context and object set are created, but enumeration of the object set returns no results.
What's the error in my code? Thanks for your help.
The notes.Count() is executed against your data file (which I assume is empty). Your new object won't be added until you call context.SaveChanges().
Consider:
objectSet.AddObject(new Note()); // new object present in memory
var notes = objectSet.AsEnumerable();
var count = notes.Count(); // query against DB file;
// what's in memory at this point is irrelevant
Add context.SaveChanges() after you add new Note and assert will pass. But of course, that introduces whole new range of problems with keeping DB state the same for every test run.
That is not entirely true.
e.g. Parent / Childs
When using Context.AddObject() for Parent it won't be added to until Context.SaveChanges() is called but when adding a Child it will be added without saving (when foreign keys are set of course).
Not sure if it is a bug or if it is by design in the EF ...
The only "workaround" I see at the moment:
introduce a Client table and each object (Parent, Child) has a reference to a Client
call context.SaveChanges() (Drawback: the user has no chance to cancel the operation)
Also calling Context.ParentSet.Execute(MergeOption.AppendOnly); does not have the expected effect!
Solution/Workaround: I maintain my own list of objects for adding/removing + setting the DataSource = null and then to my internal list.
Since it is necessary to set the DataSource = null it seems that there is something strange in EF ...
I am having an issue where UrlHelper's RouteUrl method only returns an empty string when run in my tests, though function properly when executing in the real HttpContext. It is, however, finding the route - as I do properly get an exception if I try to resolve a route name which has not been defined.
I have mocked the HttpContext and friends using the code provided by Scott Hanselman/Kzu and added the code needed to bootstrap the Application's Routes into the mocked instance
To reduce the number of variables in my situation, I've written a simple test:
[Test]
public void UrlHelperReturnsCorrectUrl()
{
var controller = new MyController();
controller.SetFakeControllerContext().LoadUrlHelper();
Assert.AreEqual("My/Route/Path", controller.Url.RouteUrl("MyRoute"));
}
Interestingly enough, accessing the RouteCollection directly and using VirtualPath does work:
[Test]
public void GetVirtualPathReturnsCorrectUrl()
{
var controller = new AccountController();
controller.SetFakeControllerContext().LoadUrlHelper();
Assert.AreEqual("My/Route/Path",
Controller.Url.RouteCollection["MyRoute"]
.GetVirtualPath(
controller.Url.RequestContext,
new RouteValueDictionary())
.VirtualPath);
}
For reference, Here is my implementation of the LoadUrlHelper extension method:
public static Controller LoadUrlHelper(this Controller controller)
{
var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
controller.Url = new UrlHelper(
controller.ControllerContext.RequestContext,
routes);
return controller;
}
And here is my route as defined in my application's Global.asax:
routes.MapRoute(
"MyRoute", "My/Route/Path",
new {controller = "Home", action = "Index"});
Has anyone run into this? Am I missing something?
EDIT:
I've followed the MVC code down to the point that it hands the route processing off to System.Routing and found something very interesting. The code that MVC eventually runs to lookup the desired URL (condensed, of course) returns an empty string:
Controller.Url.RouteCollection.GetVirtualPath(
Controller.Url.RequestContext,
"MyRoute", new RouteValueDictionary()).VirtualPath;
whereas an extremely similar variant returns the expected string:
Controller.Url.RouteCollection["MyRoute"].GetVirtualPath(
Controller.Url.RequestContext,
new RouteValueDictionary()).VirtualPath;
I can't seem to go any further in the underlying code to see what is actually happening differently here, but thought it might help someone understand what setup I am missing. (I'm not going to yell bug yet, as the fact stands that the UrlHelpers do work when in a real HttpContext)
The solution to my problem was already posted to another SO question.
I had tried to incorporate this solution piece-meal earlier but did so poorly. Once I copied it entirely and modified for my situation, it worked perfectly.
Here is a more generic version that can be reused across many tests (if placed in a base test fixture class or something similar).
Usage:
var controller = GetController<MyController>();
controller.MyAction();
//...
Method:
protected T GetController<T>() where T : Controller, new()
{
var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
request.SetupGet(x => x.ApplicationPath).Returns("/");
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost", UriKind.Absolute));
request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns((string p) => p);
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);
var controller = new T();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes);
return controller;
}