My application is an ASP.NET Core 1.0 Web API. I would like to test the following method (snipped):
public async Task<bool> GetClientsAsync()
{
foreach (var user in await this.clientAdapter.Users().ToListAsync())
{
return true;
}
return false;
}
Normally the clientAdapter is calling UserManager<IdentityUser>'s property Users. So the code for the "real" clientAdapterlooks like that:
public IQueryable<IdentityUser> Users()
{
return this.userManager.Users;
}
Now when I am testing the clientAdapter looks like the following:
private readonly List<IdentityUser> clientList;
public TestClientAdapter(){
this.clientList= this.CreateClientList();
}
public IQueryable<IdentityUser> Users()
{
return this.userList.AsQueryable();
}
The return type of the method Users() has to be IQueryable<IdentityUser> since thats the return value of the original class UserManager<IdentityUser>. Now if I execute the test I am getting the following error, as soon as it hit's the foreach loop (the problem is the ToListAsync() call):
System.NotSupportedException: "Store does not implement IQueryableUserStore<TUser>."
If I change the loop from
foreach (var user in await this.clientAdapter.Users().ToListAsync())
{
return true;
}
to
foreach (var user in this.clientAdapter.Users().ToList())
{
return true;
}
Everything works fine.
My Problem:
I am not not able to mock the UserManager since the UserManager needs a UserStore which needs a DBContext which I dont know how to mock. And even if it was possbile to mock the DBContext, I think this would turn my unit test into an integration test and I dont want that. Plus it's probably not worth the effort. So I cannot just work with a mocked Usermanager and get the data from it.
My Question:
Is it possible to make the unit test pass, without changing the method I want to test?
EDIT
#CodeCaster:
The injected clientAdapter now looks like the following (snipped):
public class TestClientAdapter: IClientAdapter, IQueryableUserStore<IdentityUser>
{
private readonly List<IdentityUser> clientList
private UserManager<IdentityUser> testUserManager;
public TestClientAdapter: ()
{
clientList= this.CreateclientList();
this.testUserManager = new UserManager<IdentityUser>(this, null, null, null, null, null, null, null, null);
}
public IQueryable<IdentityUser> Users()
{
return this.testUserManager.Users;
}
IQueryable<IdentityUser> IQueryableUserStore<IdentityUser>.Users
{
get
{
return this.clientList.AsQueryable();
}
}
Now Iam getting another Exception:
"System.InvalidOperationException" in System.Private.CoreLib.ni.dll"
ToListAsync (among of other async methods like AnyAsync, etc.) is not a standard Linq2SQL (aka IQueryable<T>) extension method from System.Linq.*.
It's part of EntityFramework and as such it assumes certain preconditions, hence it can't work with a queryable List. Basically it's a wrapper around query.AsAsyncEnumerable() and AsAsyncEnumerable checks for the existence of IAsyncEnumerable<TSource> and/or IAsyncEnumerableAccessor<TSource> and if not there throws the invalid operation exception.
There are two things you can do...
Use EF Core InMemoryDatabase for an integration test, which was made for integration tests
Refactor your code so IQueryable<T> doesn't leak outside of your repository or command/query handlers
Technically it may be possible to create an list which implements AsAsyncEnumerable<T> but I haven't tried it and most likely not working with list.AsQueryable() since it wraps the list somewhere below...
Let the clientAdapter you inject for tests also implement IQueryableUserStore<TUser>, as the UserManager casts it to that, and if that fails, throws the mentioned exception.
Related
I'm trying to implement a web application using ASP.NET MVC and the Microsoft Unity DI framework. The application needs to support multiple user sessions at the same time, each of them with their own connection to a separate database (but all users using the same DbContext; the database schemas are identical, it's just the data that is different).
Upon a user's log-in, I register the necessary type mappings to the application's Unity container, using a session-based lifetime manager that I found in another question here.
My container is initialized like this:
// Global.asax.cs
public static UnityContainer CurrentUnityContainer { get; set; }
protected void Application_Start()
{
// ...other code...
CurrentUnityContainer = UnityConfig.Initialize();
// misc services - nothing data access related, apart from the fact that they all depend on IRepository<ClientContext>
UnityConfig.RegisterComponents(CurrentUnityContainer);
}
// UnityConfig.cs
public static UnityContainer Initialize()
{
UnityContainer container = new UnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
return container;
}
This is the code that's called upon logging in:
// UserController.cs
UnityConfig.RegisterUserDataAccess(MvcApplication.CurrentUnityContainer, UserData.Get(model.AzureUID).CurrentDatabase);
// UnityConfig.cs
public static void RegisterUserDataAccess(IUnityContainer container, string databaseName)
{
container.AddExtension(new DataAccessDependencies(databaseName));
}
// DataAccessDependencies.cs
public class DataAccessDependencies : UnityContainerExtension
{
private readonly string _databaseName;
public DataAccessDependencies(string databaseName)
{
_databaseName = databaseName;
}
protected override void Initialize()
{
IConfigurationBuilder configurationBuilder = Container.Resolve<IConfigurationBuilder>();
Container.RegisterType<ClientContext>(new SessionLifetimeManager(), new InjectionConstructor(configurationBuilder.GetConnectionString(_databaseName)));
Container.RegisterType<IRepository<ClientContext>, RepositoryService<ClientContext>>(new SessionLifetimeManager());
}
}
// SessionLifetimeManager.cs
public class SessionLifetimeManager : LifetimeManager
{
private readonly string _key = Guid.NewGuid().ToString();
public override void RemoveValue(ILifetimeContainer container = null)
{
HttpContext.Current.Session.Remove(_key);
}
public override void SetValue(object newValue, ILifetimeContainer container = null)
{
HttpContext.Current.Session[_key] = newValue;
}
public override object GetValue(ILifetimeContainer container = null)
{
return HttpContext.Current.Session[_key];
}
protected override LifetimeManager OnCreateLifetimeManager()
{
return new SessionLifetimeManager();
}
}
This works fine as long as only one user is logged in at a time. The data is fetched properly, the dashboards work as expected, and everything's just peachy keen.
Then, as soon as a second user logs in, disaster strikes.
The last user to have prompted a call to RegisterUserDataAccess seems to always have "priority"; their data is displayed on the dashboard, and nothing else. Whether this is initiated by a log-in, or through a database access selection in my web application that calls the same method to re-route the user's connection to another database they have permission to access, the last one to draw always imposes their data on all other users of the web application. If I understand correctly, this is a problem the SessionLifetimeManager was supposed to solve - unfortunately, I really can't seem to get it to work.
I sincerely doubt that a simple and common use-case like this - multiple users logged into an MVC application who each are supposed to access their own, separate data - is beyond the abilities of Unity, so obviously, I must be doing something very wrong here. Having spent most of my day searching through depths of the internet I wasn't even sure truly existed, I must, unfortunately, now realize that I am at a total and utter loss here.
Has anyone dealt with this issue before? Has anyone dealt with this use-case before, and if yes, can anyone tell me how to change my approach to make this a little less headache-inducing? I am utterly desperate at this point and am considering rewriting my entire data access methodology just to make it work - not the healthiest mindset for clean and maintainable code.
Many thanks.
the issue seems to originate from your registration call, when registering the same type multiple times with unity, the last registration call wins, in this case, that will be data access object for whoever user logs-in last. Unity will take that as the default registration, and will create instances that have the connection to that user's database.
The SessionLifetimeManager is there to make sure you get only one instance of the objects you resolve under one session.
One option to solve this is to use named registration syntax to register the data-access types under a key that maps to the logged-in user (could be the database name), and on the resolve side, retrieve this user key, and use it resolve the corresponding data access implementation for the user
Thank you, Mohammed. Your answer has put me on the right track - I ended up finally solving this using a RepositoryFactory which is instantiated in an InjectionFactory during registration and returns a repository that always wraps around a ClientContext pointing to the currently logged on user's currently selected database.
// DataAccessDependencies.cs
protected override void Initialize()
{
IConfigurationBuilder configurationBuilder = Container.Resolve<IConfigurationBuilder>();
Container.RegisterType<IRepository<ClientContext>>(new InjectionFactory(c => {
ClientRepositoryFactory repositoryFactory = new ClientRepositoryFactory(configurationBuilder);
return repositoryFactory.GetRepository();
}));
}
// ClientRepositoryFactory.cs
public class ClientRepositoryFactory : IRepositoryFactory<RepositoryService<ClientContext>>
{
private readonly IConfigurationBuilder _configurationBuilder;
public ClientRepositoryFactory(IConfigurationBuilder configurationBuilder)
{
_configurationBuilder = configurationBuilder;
}
public RepositoryService<ClientContext> GetRepository()
{
var connectionString = _configurationBuilder.GetConnectionString(UserData.Current.CurrentPermission);
ClientContext ctx = new ClientContext(connectionString);
RepositoryService<ClientContext> repository = new RepositoryService<ClientContext>(ctx);
return repository;
}
}
// UserData.cs (multiton-singleton-hybrid)
public static UserData Current
{
get
{
var currentAADUID = (string)(HttpContext.Current.Session["currentAADUID"]);
return Get(currentAADUID);
}
}
public static UserData Get(string AADUID)
{
UserData instance;
lock(_instances)
{
if(!_instances.TryGetValue(AADUID, out instance))
{
throw new UserDataNotInitializedException();
}
}
return instance;
}
public static UserData Current
{
get
{
var currentAADUID = (string)(HttpContext.Current.Session["currentAADUID"]);
return Get(currentAADUID);
}
}
public static UserData Get(string AADUID)
{
UserData instance;
lock(_instances)
{
if(!_instances.TryGetValue(AADUID, out instance))
{
throw new UserDataNotInitializedException();
}
}
return instance;
}
I have a test where I pass in an object like so:
var repo = new ActualRepo();
var sut = new Sut(repo);
In my test, Repo has one method that I need to actually execute, whilst another method I want to mock out and not execute.
So for example, take this pseudocode:
var repo = new Mock<IRepo>();
repo.Setup(m => m.MethodIWantToCall()).WillBeExecuted();
repo.Setup(m => m.MethodIWantToMock()).Returns(false);
Using Moq, is this possible and how can it be done?
EDIT:
I've used TypeMock in the past and you can do something like.
Isolator.When(() => repo.MethodToIgnore()).WillBeIgnored();
Isolator.When(() => repo.MethodToActuallyRun()).WillBeExecuted();
Not too sure from the question if this is useful but it is possible to partially mock an object if the method that you want to mock is virtual.
public class Foo {
public string GetLive() {
return "Hello";
}
public virtual string GetMock() {
return "Hello";
}
}
public class Snafu {
private Foo _foo;
public Snafu(Foo foo) {
_foo = foo;
}
public string GetMessage() {
return string.Format("{0} {1}", _foo.GetLive(), _foo.GetMock());
}
}
[TestMethod]
public void NotMocked() {
var snafu = new Snafu(new Foo());
Assert.AreEqual("Hello Hello", snafu.GetMessage());
}
[TestMethod]
public void Mocked() {
var mockFoo = new Mock<Foo>();
mockFoo.Setup(mk => mk.GetMock()).Returns("World");
var snafu = new Snafu(mockFoo.Object);
Assert.AreEqual("Hello World", snafu.GetMessage());
}
You can't do this with Moq if you use the same object unless one of the method is virtual and you are basing your mock on a type rather than an interface.
That's because when you are passing a mock object based on an interface, you aren't passing a real object so it does not have access to the real methods of the object.
You are passing a dynamic proxy which will respond to methods it has been setup to respond to.
I believe TypeMock rewrites the assemblies at runtime to achieve this, something Moq definitively doesn't do.
If you want to achieve similar results with Moq:
You could mock both methods
You would have to extract both methods to different dependencies so as to mock one dependency and not the other.
You could have the method you need mocked be virtual, which would be the solution I would prefer.
EDIT : I edited my answer for correctness after reading AlanT's answer.
I want to write unit test for a class that contains linq to sql codes . I mean inside each method I have created a new DbContext and done database jobs .
I searched the web . first I came to use repository and Unit of Work patterns but I figured out that DbContext itself is a unit of work and its dbset works as repositories . another point is that I think there is no need to test Linq part because it works as it should ( tested by .net team ) . I want to test the logic I have added to the code . so I decided to create an interface with necessary methods with two implementations , one uses linqToSql while another is just a mock . something like this :
public interface IDbManager
{
bool Insert(MyEntity newEntity);
}
public class RealDbManager:IDbManager
{
public bool Insert(MyEntity newEntity)
{
using (DbDataContext db = new DbDataContext())
{
db.MyEntities.InsertOnSubmit(newEntity);
db.SubmitChanges();
}
}
}
public class MockDbManager:IDbManager
{
public bool Insert(MyEntity newEntity)
{
return true;
}
}
is the whole idea correct ? if so is this a correct implementation ?
is it possible to define DbDataContext as a class variable instead of creating new instance inside each method ?
You have the right general idea for a start. Your Mock Insert method should save the entity to some in-memory store so that subsequent queries will return the inserted information, as would be expected. But the very basic idea of having an interface, with a 'real' and a 'mock' implementation is there.
Remember that when using your Mock in tests, you are testing your other code that uses the mock - not the mock itself.
As for defining the DataContext as a member variable; you could use an IDisposable pattern for it, like so:
public class RealDbManager:IDbManager, IDisposable
{
DbDataContext db = new DbDataContext();
public bool Insert(MyEntity newEntity)
{
{
db.MyEntities.InsertOnSubmit(newEntity);
db.SubmitChanges();
}
}
public void Dispose()
{
db.Dispose();
}
}
You would just have to be sure to dispose of your DbManager, then.
Yes. The only thing I would avoid is to create an actual mocked class (in this case it should be called Fake), but using a mocking engine.
In your question you mention two kind of tests. First is testing the behavior of your class, the second is testing the integration of it. They seem the same but it's not.
In the first you need to mock your class to test its 'connection' against your other classes this way (using Moq):
[Test]
public void Test()
{
var entity = new Entity();
var mocked = new Mock<IDbManager>();
//you are telling the moq engine everytimes it finds an invocation of your repository
//to return true as you did in you mocked class
mocked.Setup( x => x.Insert( entity ) ).Returns( true );
var classUnderTest = new ClassUnderTest( mocked.Object );
//in this method you invoke your repository
var ret = classUnderTest.DoSomething( entity );
//assertions
Assert.Equal( something, ret);
//eventually you can verify that your repository has been hit once
mocked.Verify( x => x.Insert( It.IsAny<Entity>), Times.Once);
}
in the later as you correctly state, you have nothing to test on linq (Microsoft did it for us), but in case you need to verify the correctness of your linq you can do it only against a real db (or using a repository pattern against a fake repository). This is an integration test and it's has nothing to share with mocking.
To decouple your class from DbContext you could use repository pattern. Have a look at this article. http://dotnetspeak.com/index.php/2011/03/repository-pattern-with-entity-framework/
I have an ASP.NET website project that until recent had all code in App_Code folder. It uses Entity Framework 4 as ORM. Application is divided into three "sections" (let's say one for each customer). Each section has it's own database (but same schema). This is due to performance reasons, databases are over 10GB each with millions of rows.
Each time a context object is created a Session variable which holds section ID is called and proprietary connection string is chosen for this context.
It looks like this (following are members of static Connection class):
public static MyEntities GetEntityContext()
{
if (HttpContext.Current.Session["section"] == null)
{
HttpContext.Current.Response.Redirect("~/Login.aspx");
}
var context = new MyEntities(GetEntityConnectionStringForSection((int)HttpContext.Current.Session["section"]);
return context;
}
private static string GetEntityConnectionStringForSection(int section)
{
switch (section)
{
case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
}
}
It works very good and also handles situation when session timed out everytime any data access is performed.
Recently as I needed to share DB classes among two websites I moved all DB classes to separate class library and referenced System.Web library which I know is bad practice, but it's working.
Now the next step is to include unit and module tests which as I read is very difficult or impossible when using HttpContext in library, so I want to get rid of System.Web references. What is the best practice for this situation?
I think I can't just pass HttpContext to GetEntityContext() as it is also called from within my entity classes. Although this probably can be refactored. So maybe this is where I should go?
I also wondered if is it possible to somehow pass current section ID to this whole library? It cannot be just static property because as far as I understand it would be common for all users using the application. This should be user-specific.
Reassuming the objective is to make automated testing possible without loosing transparent Connection String choosing and session timeouts handling.
If I do something fundamentally wrong at this stage please also let me know. I can look again at this question tomorrow morning (8.00 am UTC) so please don't be discouraged by my silence till then.
EDIT:
Example of usage of Connection class in the library:
public partial class Store
{
public static List<Store> GetSpecialStores()
{
using (var context = Connection.GetEntityContext())
{
return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
}
}
}
You can declare interface IContextProvider inside your library ans use it to retrieve context. Something like:
public interface IContextProvider
{
MyEntities GetEntityContext();
}
This will make your library testable. In your web project you can inject IContextProvider implementation into your library.
public class WebContextProvider : IContextProvider
{
public MyEntities GetEntityContext()
{
if (HttpContext.Current.Session["section"] == null)
HttpContext.Current.Response.Redirect("~/Login.aspx");
int sectionId = (int)HttpContext.Current.Session["section"];
string connectionString = GetEntityConnectionStringForSection(sectionId);
var context = new MyEntities(connectionString);
return context;
}
private static string GetEntityConnectionStringForSection(int section)
{
switch (section)
{
case 1: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
case 2: return ConfigurationManager.ConnectionStrings["entity_2"].ConnectionString;
case 3: return ConfigurationManager.ConnectionStrings["entity_3"].ConnectionString;
default: return ConfigurationManager.ConnectionStrings["entity_1"].ConnectionString;
}
}
}
Inject this interface to repositories or other data access classes.
public partial class Store
{
private IContextProvider contextProvider;
public Store(IContextProvider contextProvider)
{
this.contextProvider = contextProvider;
}
public List<Store> GetSpecialStores()
{
using (var context = contextProvider.GetEntityContext())
{
return context.Stores.Where(qq => qq.Type > 0).OrderBy(qq => qq.Code).ToList();
}
}
}
I'm trying to start using Unit Testing and I want to test the following Controller:
public class AjaxController : Controller
{
...
public JsonResult RateVideo( int userRating, long videoId )
{
string userName = User.Identity.Name;
...
}
}
I have a created a TestClass with the following method:
[ TestMethod
public void TestRateVideo()
{
//Arrange
AjaxController c = new AjaxController();
//Act
JsonResult jr = c.RateVideo(1, 1);
//Assert
//Not implemented yet
}
I select debug and run the test. When the code reaches the 1st statement:
string username = User.Identity.Name;
Debugging stops and I am presented with a message that says that the test failed.
Any guidance you can offer would be appreciated.
The most common problem testing Controllers is using functions that rely on the HttpContext.
The implementation of the User property is something like:
public IPrincipal get_User()
{
if (this.HttpContext != null)
{
return this.HttpContext.User;
}
return null;
}
As you can see, User will return null because the HtppContext has not being initialized and calling .Identity will throw an exception.
Fortunately MVC lets you set the ControllerContext property so you can create your own instance with a mocked HttpContext.
The MVCContrib project has some test helpers. You can use the TestControllerBuilder in MVCContrib.TestHelper.dll to build your controllers inside your test classes with mocked context.