I am trying to write my first unit test for one of my service layers. I am using nunit and moq (latest versions).
I have a repo but I will mock that out that is no problem.
public void Create(string email, int id)
{
User user = Repo.GetUserByEmail(email); // mock this out. and return a mocked user.
if user != null)
{
// check permission
var clearence = GetPermissions(user, PermissionTypes.Add, id);
// some other stuff
}
}
private static List<Permissions> GetPermissions(User user, PermissionTypes PermissionNeeded, int id)
{
List<PermissionLevel> clearence = user.PermissionLevels.Where(u => u.id == id &&
(u.Permission.Name == PermissionNeeded || u.Permission.Name == PermissionTypes.Owner)).ToList();
return clearence;
}
So that is what I have.
Now what is getting me is this clearance. I am not sure how to do it. I am not sure if I have to make a user object that has a permissionLevels in it that contains a id.
I am not sure if I could mock it up but I doubt it since it is private.
The second problem is I am not sure how to create an "id" as the "id" is in a domain class that has a private set because well that was the standard used for nhibernate.
So I am not sure how to get around that.
Yes, assuming you're mocking GetUserByEmail, you can have it return a user that contains a sample set of permissions.
I would wrap the Repo.GetUserByEmail method in a separate class and inject this into your class. Something like this:
public class YourClass
{
private readonly UserProvider _userProvider;
public TestedClass(UserProvider userProvider)
{
_userProvider = userProvider;
}
public void Create(string email, int id)
{
User user = _userProvider.GetUser(email, PermissionTypes.Add, id); // mock this out. and return a mocked user.
if (user != null)
{
// check permission
var clearence = GetPermissions(user, PermissionTypes.Add, id);
// some other stuff
}
}
}
public class UserProvider
{
public User GetUser(string email, PermissionTypes.Add, id)
{
return Repo.GetUserByEmail(email);
}
}
Thus, you can stub the UserProvider class and always have full control over the user in the test.
Remember to test the UserProvider class as well ;o)
Regards,
Morten
Related
I have IDataService that contains generic crud operations
public interface IDataService<T>
{
Task<IEnumerable<T>> GetAll();
Task<IEnumerable<T>> GetAll(string[] includes = null);
Task<T> GetById(int id);
Task<T> Create(T entity);
Task<T> Update(int id, T entity);
Task<bool> Delete(int id);
}
and I have class GenericDataService<T> that implements the IDataService interface:
public class GenericDataService<T> : IDataService<T> where T : DomainObject
{
private readonly DeployToolDBContexFactory _contexFactory;
public GenericDataService(DeployToolDBContexFactory contexFactory)
{
_contexFactory = contexFactory;
}
public async Task<T> Create(T entity)
{
using (DeployToolDBContex contex = _contexFactory.CreateDbContext())
{
EntityEntry<T> createdResult = await contex.Set<T>().AddAsync(entity);
await contex.SaveChangesAsync();
return createdResult.Entity;
}
}
public async Task<bool> Delete(int id)
{
using (DeployToolDBContex contex = _contexFactory.CreateDbContext())
{
T entity = await contex.Set<T>().FirstOrDefaultAsync((e) => e.Id == id);
contex.Set<T>().Remove(entity);
await contex.SaveChangesAsync();
return true;
}
}
public async Task<IEnumerable<T>> GetAll()
{
using (DeployToolDBContex contex = _contexFactory.CreateDbContext())
{
IEnumerable<T> entities = await contex.Set<T>().ToListAsync();
return entities;
}
}
public async Task<T> GetById(int id)
{
using (DeployToolDBContex contex = _contexFactory.CreateDbContext())
{
T entity = await contex.Set<T>().FirstOrDefaultAsync((e) => e.Id == id);
return entity;
}
}
public async Task<T> Update(int id, T entity)
{
using (DeployToolDBContex contex = _contexFactory.CreateDbContext())
{
entity.Id = id;
contex.Set<T>().Update(entity);
await contex.SaveChangesAsync();
return entity;
}
}
public async Task<IEnumerable<T>> GetAll(string[] includes = null)
{
using (DeployToolDBContex contex = _contexFactory.CreateDbContext())
{
var query = contex.Set<T>().AsQueryable();
foreach (var include in includes)
query = query.Include(include);
return query.ToList();
}
}
}
To create objects I'm using a data store class that executes operations with the DataService object:
public class DataStore
{
private static DataStore instance = null;
public static DataStore Instance
{
get
{
instance = instance == null ? new DataStore() : instance;
return instance;
}
}
public IDataService<User> userDataService;
public DataStore()
{
this.userDataService = new GenericDataService<User>(new DeployToolDBContexFactory());
}
}
For example, user creation :
private async void AddUser()
{
User user = new User()
{
UserName = UserNameTxt,
RoleId = RoleSelected.Id
};
await DataStore.Instance.userDataService.Create(user);
}
I'm new to Moq and I want to write unit tests, for example, test of user creation
[Test]
public async Task CreateUser()
{
Mock<DeployToolDBContexFactory> dbContextFactory = new Mock<DeployToolDBContexFactory>();
Mock<DeployToolDBContex> dbContextMock = new Mock<DeployToolDBContex>(dbContextFactory.Object);
var user = new User()
{
UserName = "testName"
};
var mock = new Mock<GenericDataService<User>>(new DeployToolDBContexFactory());
mock.Setup(m => m.Create(user)).ReturnsAsync(new User() { UserName = user.UserName}).Verifiable();
var service = new GenericDataService<User>(dbContextFactory.Object);
User u = await service.Create(user);
Assert.AreEqual(u.UserName , user.UserName);
}
I'm getting this error :
System.NotSupportedException : Unsupported expression: m => m.Create(user)
Non-overridable members (here: GenericDataService.Create) may not be used in setup / verification expressions.
I tried to set DbSet as virtual.
Thanks for any help.
It looks like you are a bit mixed up with mocking and what exactly you should be testing. Your GenericDataService is essentially a Generic Repository pattern. This is actually an anti-pattern for EF, but there is plenty to read up on why you shouldn't use it with EF... Repository patterns in general are a good thing for facilitating unit testing, however this is because they serve as a boundary to avoid needing to try and mock a DbContext and its DbSets.
Firstly, your Test is testing the wrong thing. The test should be testing whatever method that will be calling your AddUser method. Whether this is in a Controller or a Service, etc. That controller would have a dependency of IDataService<User> declared which we would be mocking in order to test the controller:
For the sake of argument I've made AddUser() a public method. In your case you should have a public action or method that calls AddUser and would set up a test for that method. You should also structure your code to avoid being dependent on module-level state. For instance an AddUser method should not be reliant on private/protected state, it should ultimately be getting parameters to do things like perform actions or modify state. (kept to a minimum)
So let's assume we want to test a method that should call the DataService Create method and Create is expected to have added the item to the DBContext and assigned an ID. The purpose of the unit test is not to assert what EF actually does, but rather what the code under test should do with the results:
[Test]
public void EnsureAddUserCreatesUser()
{
const string userName = "New User";
const int roleId = 4;
const int UserId = 101;
var mockUserDataService = new Mock<IDataService<User>>();
mockUserDataService.Setup(m => m.Create(It.IsAny<User>())).Callback(m => {m.UserId = userId;});
var testController = new UserController(mockUserDataService.Object);
var user = await testController.AddUser(userName, roleId);
Assert.IsNotNull(user);
Assert.AreEqual(userId, user.UserId);
Assert.AreEqual(userName, user.UserName);
Assert.AreEqual(roleId, user.RoleId);
mockUserDataService.Verify(m => m.Create(It.IsAny<User>()), Times.Once);
}
What a test like this does is set up a mock of our repository/data service telling it to expect its input parameter. Since our AddUser method will be creating a new user based on some values, we tell it to expect It.IsAny<User>() which says "expect a user". From there we can have the mock perform some basic actions as if the DbContext added our user successfully such as populating a PK. This example populates the PK using the Callback method which accepts whatever User was passed in then sets our known PK. The value itself does not matter since we aren't actually inserting data, we just want a known value to get back that we can assert that the mock was actually called. Normally the AddUser might also expect to check the resulting data and return something like a success state with an ID. In this example I had the AddUser return the User. Other tests you might want to assert the behaviour if the AddUser attempts to add a duplicate user. In these cases the Moq might Throw an exception or otherwise return a different result.
From there we have returned the User, so we just assert the values are what were expected, including the PK, and that our mocked method was actually called.
Ultimately when it comes to unit testing, the key points are:
Your DataService/Repository serves as the boundary for the tests. (What you mock)
Your tests test business logic above this boundary.
Your tests mock the boundary, capturing all expected calls to that boundary, and either return known state, take action on passed in state, or throw exceptions based on what behaviour you want to test.
Your tests can then assert the mocks to verify that methods that were expected to be called were called, and any methods that were not expected to be called were not called. (Times.None)
I'm trying to create better separation of concerns for code reuse in my program, that way I don't have a bloated controller that does all these different things.
for instance, in my application I have a user profile where users can upload a profile pic. If they don't customize their profile pic, I set the default profile pic to an avatar. I do this through a method to check if their profile pic string is null.
I created a folder called HelperMethods and created a class called UserHelperMethods which currently has one function:
namespace HiRatik.Stories.HelperMethods
{
public class UserHelperMethods
{
//checks if the user's profile pic is null and sets it to default pic if it is
public string GetUserProfilePic(ApplicationUser user)
{
if (user.ProfilePic == null)
{
user.ProfilePic = "profile_pic_default.png";
}
return user.ProfilePic;
}
}
}
Now, in the controller, under the controller's folder, I added using HiRatik.Stories.HelperMethods;
and tried to call the public function GetUserProfilePic from the UserController. But I'm getting an error on the implementation. I'd like to be able to place a lot of these general functions related to users in another class like UserHelperMethods to clean up the bulk in the controller, but I'm missing something on the implementation. the using statement at the top is grayed out, so it's not picking up the function call. Any ideas?
You need to add an instance of the helper method class to every class you want to use it in.
UserHelpMethods helper = new UserHelperMethods();
then you can use it as:
helper.GetUserProfilePic(foundUser);
...
help.DoSomethingImportant(foundUser);
You may want to make this into an Extension. Then you will be able to call it like this:
user.GetProfilePic();
The changes you have to do is, to make both your class and method static and have the this keyword before the parameter. Something like
public static class ApplicationUserExtensions
{
//checks if the user's profile pic is null and sets it to default pic if it is
public static string GetProfilePic(this ApplicationUser user)
{
if (user.ProfilePic == null)
{
user.ProfilePic = "profile_pic_default.png";
}
return user.ProfilePic;
}
}
I would consider making these methods static.
namespace HiRatik.Stories.HelperMethods
{
public class UserHelperMethods
{
//checks if the user's profile pic is null and sets it to default pic if it is
public static string GetUserProfilePic(ApplicationUser user)
{
if (user.ProfilePic == null)
{
user.ProfilePic = "profile_pic_default.png";
}
return user.ProfilePic;
}
}
}
If the helper methods don't rely on any state within the UserHelperMethods object, this will make it much easier to call your methods from anywhere, as there is no longer a need to create an instance of the UserHelperMethods type. You can call the method like this.
UserHelperMethods.GetUserProfilePic(foundUser);
just create instance of the class
var myInstance = new UserHelperMethods();
then just use myInstance object to access the functions in UserHelpMethods class
so you can call any function in UserHelpMethods like this
myInstance.FunctionName();
so in your case it will be like
myInstance.GetUserProfilePic(foundUser);
you could update your code to one of the following
A -
namespace HiRatik.Stories.HelperMethods
{
public class UserHelperMethods
{
private static UserHelperMethods _instance = null;
public static UserHelperMethods Instance()
{
if(_instance == null)
{
_instance = new UserHelperMethods();
}
return _instance;
}
//checks if the user's profile pic is null and sets it to default pic if it is
public string GetUserProfilePic(ApplicationUser user)
{
if (user.ProfilePic == null)
{
user.ProfilePic = "profile_pic_default.png";
}
return user.ProfilePic;
}
}
}
and inside your Controller just use call it like this
UserHelperMethods.Instance().GetUserProfilePic(founduser);
Or the easiest way
var helperObj = new UserHelperMethods();
helperObj.GetUserProfilePic(founduser);
the diff you won't need to create instance all the time in diff controllers
I wish this help you !!
I want to implement a login process within the Onion Architecture. I can't get my head around how to go about it correctly. Below is my Repository class that will talk to the database. How would I go about checking that an email had not already been entered into the table. It seems the only parameters I can pass in are Model objects or entities from my BaseClass. My Base class contains only a string for Id.
public class RentalsRepository<T> : IRentalsRepository<T> where T : BaseClass
{
private readonly RentalsDBContext _Context;
private DbSet<T> entities;
string errorMessage = string.Empty;
public RentalsRepository(RentalsDBContext _Context)
{
this._Context = _Context;
entities = _Context.Set<T>();
}
public T Get(string Id)
{
return entities.SingleOrDefault(e => e.Id == Id);
}
Currently all I can think of is returning all the user entries and then searching the list but I imagine this is not very efficient. Thanks!
Basically you first of all would extend your Repository with the mentioned GetByPredicatemethod that is basically only a Wrapper for SingleOrDefaultor FirstOrDefault (or other LINQ methods that take a lambda expression / predicate). Your repo will then look similar to this:
public class RentalsRepository<T> : IRentalsRepository<T> where T : BaseClass
{
private readonly RentalsDBContext _Context;
private DbSet<T> entities;
string errorMessage = string.Empty;
public RentalsRepository(RentalsDBContext _Context)
{
this._Context = _Context;
entities = _Context.Set<T>();
}
public T Get(string Id)
{
return entities.SingleOrDefault(e => e.Id == Id);
}
public T GetByPredicate(Func<T, bool> predicate)
{
return entities.FirstOrDefault(predicate);
}
}
In your Businesslogic you would then call this method like so:
public void PerformLogin(string username, string hashedPassword)
{
var user = _repository.GetByPredicate(x => x.Username == username);
if(user != null)
{
if(user.HashedPassword == hashedPassword)
{
// Login succeeded do all you need to set usersession here
return;
}
}
// If we´ve come this far either there is no user or password was incorrect. We need to inform the user that login hasn´t succeeded
throw new LoginFailedException("Login failed. Username does not exist or password is incorrect.);
}
Basically as you can call this GetByPredicateanyway you want. Please consider that each call to GetByPredicatwill result in a SQL expression so do not use to complex conditions. Only use simple conditions like the one I´ve been showing above.
Hi i`m having trouble with a website. Sometimes after the Login my Site redirects me to the Login-Page saying i´m not having the rights to use this function, please login.
Ok first i thought, somethign wrong with my Accesrights but thats not, if i just go back one site in the Browser and send the Request again, it works.
So i debugged it, and after a ton of tests i got a result finding out, that when i create my Service Context with Ninject the UserName is an empty string.
Here is my Code:
First my Interface IServiceContext:
public interface IServiceContext
{
string UserName { get; }
}
Then the Class ServiceContext:
public class ServiceContext : IServiceContext
{
private static Object _syncRoot = new Object();
private static long _instance = 0;
private long _currentInstance = 0;
public string UserName { get; private set; }
public ServiceContext()
{
lock (_syncRoot)
{
if (_instance >= long.MaxValue)
_instance = 0;
_currentInstance = _instance++;
}
if (System.Web.HttpContext.Current.User == null)
UserName = "";
else
UserName = System.Web.HttpContext.Current.User.Identity.Name;
}
public ServiceContext(string userName)
{
UserName = userName;
}
public override string ToString()
{
return string.Format("#{0}, UserName: {1}", _currentInstance, UserName);
}
}
My Binding is set in a seperate file, looks like:
Bind<SecurityManagement >().ToSelf().InTransientScope();
Rebind<IServiceContext>().To<ServiceContext>().InRequestScope();
I need to use rebind, cause in my framework a StandardBinding for serviceContext is made.
And the Call from my InvokeMethod:
class SecurityManagement : IInterceptor
{
public void Intercept(IInvocation invocation)
{
IServiceContext _context = _kernel.Get<IServiceContext>();
String name = System.Web.HttpContext.Current.User.Identity.Name;
}
}
So Sometimes it happens, that my _context.UserName is an empty String. I found out that the System.Web.HttpContext.Current.User.Identity.Name property is an Empty string whenn Injecting into ServiceContext, but the Variable Name has the right Username. It is no Option for me to make the setter for the Property UserName public cause of the framework i´m using.
So anybody an idea why this is happening? perhaps any idea to solve the problem
Accessing straight to System.Web.HttpContext inside Service Layer and Repository Layer is not a good practice, because it is hard to unit test your project.
Instead, you want to inject HttpContextBase via constructor.
public class ServiceContext : IServiceContext
{
HttpContextBase _httpContextBase,
public ServiceContext(HttpContextBase httpContextBase)
{
_httpContextBase = httpContextBase;
}
}
Then access user like this -
string username = _httpContextBase.User.Identity.Name;
I'm not familiar with mocking. I'd like test if my method GetById return me an object User with an Id. Below the code, I'd like test if the GetById(10) return me an User with id = 10.
I set the moq (I hope it's correct) but how execute the moq ?
Thanks,
[TestMethod]
public void MyMoq()
{
var userMock = new Mock<IUsers>();
userMock.Setup(x => x.GetById(10)).Returns(new User());
//After ?
new Users().GetById(10);
}
public interface IUsers
{
IUser GetById();
}
public IUser GetById(int id)
{
using (var context = ....)
{
//code here
//return user here
}
}
Alright, as I said in comments, it's not clear for me what code you're trying to test. I see two options here.
1) The Users class implements IUsers interface and your intention is to test implementation of GetById(int) method.
In such case you do NOT need to mock the 'Users#GetById(id)' method, you just need to call it and check the result.
The code should look similar to:
interface IUser
{
int Id { get; }
}
class User : IUser
{
public int Id { get;set; }
}
interface IUsers
{
IUser GetById(int id);
}
class Users : IUser
{
public IUser GetById(int id)
{
// TODO: make call db call
// TODO: parse the result
// TODO: and return new User instance with all the data from db
return new User{ Id = id };
}
}
[TestMethod]
public void MyMoq()
{
// TODO: prepare/mock database. That's whole another story.
var users = new Users();
// act
var user = users.GetById(10);
// assert
Assert.AreEqual(10, user.Id);
}
2) Your Users#GetById(int) method is supposed to call the IUsers#GetById(int) and return the result. In such case you need to create mock of IUsers(as you've shown in question) and pass it to Users. The code should be(sorry for possible duplication):
interface IUser
{
int Id { get; }
}
class User : IUser
{
public int Id { get;set; }
}
interface IUsers
{
IUser GetById(int id);
}
class Users : IUser
{
private readonly IUser _users;
public Users(IUser users)
{
_users = users;
}
public IUser GetById(int id)
{
// next line of code is to be tested in unit test
return _users.GetById(id);
}
}
[TestMethod]
public void MyMoq()
{
var usersMock = new Mock<IUsers>();
usersMock.Setup(x => x.GetById(10)).Returns(new User());
var users = new Users(usersMock.Object);
// act
var user = users.GetById(10);
// assert
Assert.AreEqual(10, user.Id);
}
p.s. Could be useful to take a look at moq tutorial and The Art of Unit Testing book, Part 2 - Core techniques(page 47) - stubs, mocks, etc.
I don't quite sure what you want to test. You also has Mock class with some methods that you don't describe.
However, answering your question about mocking. Consider this class:
public class MyMoq : IUsers
{
private readonly Mock<IUsers> userMock;
public MyMoq(Mock<IUsers> userMock){
this.userMock = userMock;
}
[TestMethod]
public IUser GetById()
{
userMock.Setup(x => x.GetById(10)).Returns(new User());
//After ?
return new UsersDb().GetById(10);
}
}
To use it:
MyMoq moq = new MyMoq(new Mock<IUsers>());
User u = moq.GetById();
My assumption in this example is Mock<IUsers> is a repository and MyMoq is a service class. Also, IUser is an Entity Interface, and IUsers is a service interface.
To test userMock.Object should return the actual mocked IUsers object.
var userMock = new Mock<IUsers>();
userMock.Setup(x => x.GetById(10)).Returns(new User());
var mockobject = userMock.Object;
//Returns your mocked new User() instance
var newUserObject = mockobject.GetById(10);
In the above code, newUserObject has only created a new instance of User.
To test your GetById method, you need to call it again and Assert.
Assert.AreEqual(newUserObject.GetById(20).ID, 20); //Assume User has a property ID
Suggestion: It should be possible to have a better way to create the User instance.
GetById should be in it's own class (probably called Users) if that is what is being tested. Users could then accept a context in the constructor. Then mock this context to return stubbed data.
So in summary
Class Users implementing IUsers
Users has a constructor with parameter IContext (or whatever it would be called here)
Test class would mock IContext but not IUsers.
Call users.GetById and check the output is correct.
The way you would set up your context depends on what type of context it is, but see https://cuttingedge.it/blogs/steven/pivot/entry.php?id=84.