How to mock Asp.net identity UserManager to list user of Specific role - asp.net-mvc

I am trying to write a Unit test of index method of my ClientController.
Here is my ClientController:
public ClientController(ApplicationUserManager clientManager, ApplicationRoleManager roleManager)
{
ClientManager = clientManager;
RoleManager = roleManager;
}
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager
{
get
{
return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
}
set
{
_roleManager = value;
}
}
private ApplicationUserManager _clientManager;
public ApplicationUserManager ClientManager
{
get
{
return _clientManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
set
{
_clientManager = value;
}
}
public async Task<ActionResult> Index(string filter, string error, string searchName, int? page, int? records)
{
List<string> filterCriteria = new List<string>();
filterCriteria.Add("Choose Email");
var listClients = new List<ApplicationUser>();
// Get the list of clients ( users with client role )
foreach (var user in ClientManager.Users.Where(u => u.IsActive == true && (u.FirstNames.Contains(searchName) || u.LastName.Contains(searchName)
|| searchName == null)).OrderBy(u => u.FirstNames).ToList())
{
if (await ClientManager.IsInRoleAsync(user.Id, "Client"))
{
listClients.Add(user);
filterCriteria.Add(user.Email);
}
}
ViewBag.emails = new SelectList(filterCriteria);
ViewBag.error = error;
if (filter == null || filter.Equals("Choose Email"))
{
return View(listClients.ToList().ToPagedList(page ?? 1, records ?? 15));
}
else
{
return View();
}
And here is my attempt to write a unit test of it.
[TestMethod]
public void Index_Get_RetrievesAllClientFromRepository()
{
// Arrange,
ApplicationUser Client1 = GetClientNamed("1", 1, 1, DateTime.Now, "Abc", "Abc", "Xyz", "343433443", "abc#xyz.com", "M", "06091980-ABSD");
var userStore = new Mock<IUserStore<ApplicationUser>>();
var userManager = new UserManager<ApplicationUser>(userStore.Object);
userStore.Setup(x => x.CreateAsync(Client1))
.Returns(Task.FromResult(IdentityResult.Success));
userStore.Setup(x => x.FindByNameAsync(Client1.UserName))
.Returns(Task.FromResult(Client1));
var roleStore = new Mock<IRoleStore<IdentityRole>>();
var roleManager = new Mock<ApplicationRoleManager>(roleStore.Object);
var controller = new ClientController(
userStore.Object as ApplicationUserManager, roleManager.Object);
// Act
var resultTask = controller.Index("Choose Email", "", "", 1, 15);
resultTask.Wait();
var result = resultTask.Result;
var model = (List<ApplicationUser>)((ViewResult)result).Model;
CollectionAssert.Contains(model, Client1);
}
userStore.Object always come null. I am quite newbie in unit testing and I have looked for many solution but there isn't such use case. Any help would be appreciated.

userStore.Object is coming as null because of the as cast, which returns null if the conversion isn't possible.
userStore is defined as:
new Mock<IUserStore<ApplicationUser>>();
which means that .Object will be of type IUserStore<ApplicationUser>,
which isn't an ApplicationUserManager, so you end up with null.

Related

How do I programmatically add records to an Umbraco v8 form?

I'm looking to add records to an Umbraco v8 form. I know I need the form guid. Is this how I'd do it? Something like this?
public void PostFormData()
{
Guid FormGuid = new Guid("8494a8f0-94da-490e-bd61-7e658c226142");
var form = _formService.Get(FormGuid);
//place for field data into fieldDic
var fieldDic = new Dictionary<Guid, RecordField>();
var firstName = form.AllFields.First(f => f.Alias == "firstName");
var firstNameRecord = new RecordField(firstName);
firstNameRecord.Values = new List<object>() { "Mad Max" };
fieldDic.Add(firstName.Id, firstNameRecord);
var record = new Record()
{
Created = DateTime.Now,
Form = form.Id,
RecordFields = fieldDic,
State = FormState.Submitted,
};
record.RecordData = record.GenerateRecordDataAsJson();
_recordStorage.InsertRecord(record, form);
}
Here's how I do it. Note, I'm hard-coding the Record.UmbracoPageId to -1 while you might want to actually pass in the correct page ID.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Forms.Core.Data.Storage;
using Umbraco.Forms.Core.Models;
using Umbraco.Forms.Core.Persistence.Dtos;
using Umbraco.Forms.Core.Services;
namespace myProject.Services
{
public class FormServiceComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.Register<IFormService, FormService>(Lifetime.Request);
}
}
public interface IFormService
{
void InsertFormData(Guid formGuid, object formModel, string ipAddress);
}
public class FormService : IFormService
{
private readonly ILogger _logger;
private readonly Umbraco.Forms.Core.Services.IFormService _formService;
private readonly IRecordStorage _recordStorage;
private readonly IRecordFieldStorage _recordFieldStorage;
private readonly IWorkflowService _workflowService;
public FormService(ILogger logger, Umbraco.Forms.Core.Services.IFormService formService, IRecordStorage recordStorage, IRecordFieldStorage recordFieldStorage, IWorkflowService workflowService)
{
_logger = logger;
_formService = formService;
_recordStorage = recordStorage;
_recordFieldStorage = recordFieldStorage;
_workflowService = workflowService;
}
#region IFormService
public void InsertFormData(Guid formGuid, object formModel, string ipAddress)
{
try
{
Form form = _formService.GetForm(formGuid);
Record record = new Record();
foreach (Field field in form.AllFields)
{
string caption = CleanCaption(field.Caption);
if (formModel.GetType().GetProperty(caption) == null) continue;
var propertyValue = formModel.GetType().GetProperty(caption).GetValue(formModel, null);
if (propertyValue != null)
{
List<object> values = ExtractValues(propertyValue);
RecordField recordField = new RecordField
{
Alias = field.Alias,
FieldId = field.Id,
Field = field,
Key = Guid.NewGuid(),
Record = record.Id,
Values = values
};
_recordFieldStorage.InsertRecordField(recordField);
record.RecordFields.Add(recordField.Key, recordField);
}
}
record.Form = formGuid;
record.IP = ipAddress;
record.UmbracoPageId = -1;
record.State = Umbraco.Forms.Core.Enums.FormState.Approved;
record.RecordData = record.GenerateRecordDataAsJson();
_recordStorage.InsertRecord(record, form);
_recordStorage.DisposeIfDisposable();
}
catch (Exception ex)
{
_logger.Error<FormService>(ex, "Failed inserting Umbraco Forms data for {formGuid}");
}
}
#endregion IFormService
#region Private
private string CleanCaption(string caption)
{
Regex rgx = new Regex("[^a-zA-Z0-9 -]");
return rgx.Replace(caption.Trim().Replace(" ", ""), "");
}
private List<object> ExtractValues(object propertyValue)
{
List<object> result = new List<object>();
if (propertyValue is string == false && propertyValue.GetType().GetGenericTypeDefinition() == typeof(List<>))
{
IEnumerable<object> _propertyValue = (IEnumerable<object>)propertyValue;
if (_propertyValue.Any())
{
if (_propertyValue.First().GetType().GetProperties().Count() > 1)
{
JArray _properties = JArray.Parse(JsonConvert.SerializeObject(propertyValue));
foreach (JToken item in _properties)
{
string _value = string.Empty;
foreach (var _property in _propertyValue.First().GetType().GetProperties())
{
string _key = _property.Name;
_value = _value + (_value == "" ? "" : " - ") + item[_key].ToString();
}
result.Add(_value);
}
}
else
{
string _key = _propertyValue.First().GetType().GetProperties().First().Name;
JArray _properties = JArray.Parse(JsonConvert.SerializeObject(propertyValue));
foreach (JToken item in _properties)
{
result.Add(item[_key].ToString());
}
}
}
}
else
{
result.Add(propertyValue);
}
return result;
}
#endregion Private
}
}

Identity Server - how to I include with token additional claims (from external identity provider)

I am having a hard time finding solid information about how to send additional claims to my client application from identity server.
At the current moment, I am using the following to get a local claim (that I captured within ProcessLoginCallbackForOidc) and added to the claims being returned during authentication.
Is this the best approach?
public class ProfileService : IProfileService
{
public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
//var sub = context.Subject.GetSubjectId();
var claims = context.Subject.Claims.ToList();
if (claims.Count > 0)
{
var emailClaim = claims.FirstOrDefault(x => x.Type == "email");
if (emailClaim == null)
{
var emailAddressClaim = context.Subject.Claims.FirstOrDefault(x => x.Type == "emails");
if (emailAddressClaim != null)
{
claims.Add(new Claim("email", emailAddressClaim.Value));
}
}
}
// Set returned claims (System.Security.Claims.Claim) by setting context.IssuedClaims
context.IssuedClaims = claims;
return Task.CompletedTask;
}
public Task IsActiveAsync(IsActiveContext context)
{
context.IsActive = true;
return Task.CompletedTask;
}
}
Yes this is proper solution. ProfileService is an extensibility point to add extra claims for a user.
Its called when creating token for the user.
Read more here
Edit:
Here is sample code for profile service:
public class ProfileService : IProfileService
{
private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;
private readonly UserManager<ApplicationUser> _userManager;
public ProfileService(UserManager<ApplicationUser> userManager, IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory)
{
_userManager = userManager;
_claimsFactory = claimsFactory;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
var principal = await _claimsFactory.CreateAsync(user);
var claims = principal.Claims.ToList();
if (claims.Count > 0)
{
var emailClaim = claims.FirstOrDefault(x => x.Type == "email");
if (emailClaim == null)
{
var emailAddressClaim = context.Subject.Claims.FirstOrDefault(x => x.Type == "emails");
if (emailAddressClaim != null)
{
claims.Add(new Claim("email", emailAddressClaim.Value));
}
}
}
context.IssuedClaims = claims;
return Task.CompletedTask;
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
context.IsActive = user != null;
}
}

add role in database in asp mvc identity

i need to when user regiter add in tabel AspNetRole add user id and role id .
but when i create a user show me this error .
how can i insert role in database ?
/*************************************************************************************************/
identityconfig :
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
return new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>()));
}
}
public static class SecurityRole
{
public const string Admin = "admin";
public const string Accounting = "accounting";
}
StartupAuth :
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
AccountController :
public ApplicationRoleManager RoleManager
{
get
{
return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
}
private set
{
_roleManager = value;
}
}
public async Task<ActionResult> Register(RegisterViewModel model, HttpPostedFileBase IamgeProfile)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Username, Email = model.Email };
user.Name = model.Name;
user.Family = model.Family;
user.Address = model.Address;
user.BankName = model.BankName;
user.City = model.City;
user.Ostan = model.Ostan;
user.PhoneNumber = model.PhoneNumber;
user.HomeNumber = model.HomeNumber;
user.ShabaNo = model.ShabaNo;
user.PostaCode = model.PostaCode;
user.NationalCode = model.NationalCode;
if (IamgeProfile != null)
{
IamgeProfile = Request.Files[0];
var ext = System.IO.Path.GetExtension(IamgeProfile.FileName);
if (ext == ".jpeg" || ext == ".jpg" || ext == ".png")
{
string filename = model.Name + model.Family + model.NationalCode + ext;
IamgeProfile.SaveAs(Server.MapPath(#"~/Images/UserImageProfile/" + filename));
user.IamgeProfile = filename;
}
}
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
await UserManager.AddToRoleAsync(user.Id, role: SecurityRole.Accounting);
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking this link: link");
ViewBag.Link = callbackUrl;
return View("DisplayEmail");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
To add a role into AspNetRoles you can do this in your Seed() or other startup method:
if (!context.Roles.Any(r => r.Name == "Admin"))
{
var store = new RoleStore<IdentityRole>(context);
var manager = new RoleManager<IdentityRole>(store);
var role = new IdentityRole { Name = "Admin" };
manager.Create(role);
}
https://msdn.microsoft.com/en-us/library/dn613057(v=vs.108).aspx

ReturnsAsync in Moq is not working

Here is my code
public interface IUserManager
{
Task<int> PostUser(User user);
IQueryable<User> GetUserById(long userId);
}
public class UserManager : IUserManager
{
public UserManager(DataContext context)
{
this.DataContext = context;
}
public async Task<int> PostUser(User user)
{
this.DataContext.User.Add(user);
return await this.DataContext.SaveChangesAsync().ConfigureAwait(false);
}
public IQueryable<User> GetUserById(long userId)
{
return this.DataContext.User
.Where(userNotes => userNotes.UserId == userId).AsQueryable();
}
}
Controller:
public class UserController : BaseController
{
private readonly IUserManager userManager;
public UserController()
{
this.userManager = new UserManager();
}
public UserController(IUserManager userManager)
{
this.userManager = userManager;
}
[EnableQuery]
public IQueryable<User> Get([FromODataUri]long userId)
{
return this.userManager.GetUserById(userId);
}
public HttpResponseMessage Post(User user)
{
if (userNote == null || !ModelState.IsValid)
{
return this.BuildErrorResponse(ResponseCodes.INVALID_MISSING_INPUTS);
}
if (this.userManager.PostUser(user).Result <= 0)
{
return this.BuildErrorResponse(ResponseCodes.USER_ADD_FAILED);
}
return this.BuildSuccessResponse<User>(ResponseCodes.USER_ADDED, user);
}
}
Moq test:
[TestClass]
public class UnitTest
{
IUserManager userManagerMock;
Mock<IUserManager> iUserManagerMock;
[TestInitialize]
public void Setup()
{
//.. setup variables and mock data
userManagerMock = new UserManager(ContextMock.Object);
iUserManagerMock.Setup(u => u.PostUser(It.IsAny<User>()))
.ReturnsAsync(1);
}
[TestMethod]
public void Post()
{
var controller = new UserController(userManagerMock); //userNotesManagerMock will have the mock data //and mock methods setup
var httpResponse = controller.Post(userPostMock); //userPostMock will have mock data to save
//Assert.AreEqual(HttpResponseMessage, result);
}
}
I wrote a post method as you'd see here. I've a Get method as well which is working perfectly with mocking data.
But when I debug through the Post, the data the following statement is always returns ZERO instead of 1, which I've set up in the ReturnsAsync.
this.userManager.PostUser(user).Result <= 0 //this always gives me zero
What's wrong with the post ? Am I doing anything wrong ?
Can anyone shed some light on this
EDIT
Here is the GET version of the Test method and setup
[TestInitialize]
public void Setup()
{
//dummy data setup
UserMock = new List<User>
{
new User { //blah blah properties }
}.AsQueryable();
//context setup
dbSetUserMock = new Mock<IDbSet<User>>();
dbSetUserMock.Setup(m => m.Provider).Returns(UserMock.Provider);
dbSetUserMock.Setup(m => m.Expression).Returns(UserMock.Expression);
dbSetUserMock.Setup(m => m.ElementType).Returns(UserMock.ElementType);
dbSetUserMock.Setup(m => m.GetEnumerator()).Returns(UserMock.GetEnumerator());
UserContextMock = new Mock<DataContext>();
UserContextMock.Setup(s => s.User).Returns(dbSetUserMock.Object);
//inject the context to manager
UserManagerMock = new UserManager(UserContextMock.Object);
iUserManagerMock = new Mock<IUserManager>();
iUserManagerMock.Setup(notes => notes.PostUserNote(It.IsAny<User>()))
.ReturnsAsync(1);
}
[TestMethod]
public void Get_User_Success()
{
var controller = new UserController(UserManagerMock);
var values = controller.Get(100);
Assert.AreEqual(100, values.FirstOrDefault().UserId);
}
Get_User_Success works well now with the dummy data set and I'm able to pass the test without iUserManagerMock object. Reason being I want to execute the code inside of GetUser() method in Manager class.
And I've another question over here. As I'm setting the expected result to be 1 in the ReturnAsync for Post action. How do I build a test method for failure case scenario as the return from the POST method will still be 1 for failure case ?
You are mixing up the set up. If the method under test is the UserController.Post and you want to mock the UserManager via the IUserManager interface, then you don't need to new one up manually.
[TestClass]
public class UnitTest {
[TestMethod]
public void UserController_Should_Post_User_Ok() {
//Arrange
var userPostMock = new User { UserId = 100 };
var userManagerMock = new Mock<IUserManager>();
userManagerMock.Setup(u => u.PostUser(It.IsAny<User>())).ReturnsAsync(1);
var controller = new UserController(userManagerMock.Object);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
//Act
var httpResponse = controller.Post(userPostMock);
//Assert
Assert.AreEqual(System.Net.HttpStatusCode.OK, httpResponse.StatusCode);
}
[TestMethod]
public void UserController_Should_Post_User_Fail() {
//Arrange
var userPostMock = new User { UserId = 100 };
var userManagerMock = new Mock<IUserManager>();
userManagerMock.Setup(u => u.PostUser(It.IsAny<User>())).ReturnsAsync(0);//Replicating a failed post
var controller = new UserController(userManagerMock.Object);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
//Act
var httpResponse = controller.Post(userPostMock);
//Assert
Assert.AreEqual(System.Net.HttpStatusCode.InternalServerError, httpResponse.StatusCode);
}
[TestMethod]
public void UserManager_Should_Get_User_Success() {
//Arrange
var userMock = new List<User>
{
new User (){ UserId=100 }
}.AsQueryable();
//context setup
var dbSetUserMock = new Mock<IDbSet<User>>();
dbSetUserMock.Setup(m => m.Provider).Returns(userMock.Provider);
dbSetUserMock.Setup(m => m.Expression).Returns(userMock.Expression);
dbSetUserMock.Setup(m => m.ElementType).Returns(userMock.ElementType);
dbSetUserMock.Setup(m => m.GetEnumerator()).Returns(userMock.GetEnumerator());
var userContextMock = new Mock<DataContext>();
userContextMock.Setup(s => s.User).Returns(dbSetUserMock.Object);
//inject the context to manager
var userManagerMock = new UserManager(userContextMock.Object);
//Act
var values = userManagerMock.GetUserById(100);
//Assert
Assert.AreEqual(100, values.FirstOrDefault().UserId);
}
}

unit test fails in edit _get action

i wrote a unit test for edit_get action
My controller action is
public class GroupController : Controller
{
private readonly IGroupService groupService;
public GroupController(IGroupService groupService)
{
this.groupService = groupService;
}
public ActionResult EditGroup(int id)
{
var group = groupService.GetGroup(id);
CreateGroupFormModel editGroup = Mapper.Map<Group, CreateGroupFormModel>(group);
if (group == null)
{
return HttpNotFound();
}
return View("_EditGroup", editGroup);
}
the controller actionis working fine.
but when i am writing my unit test it get failed
my test is
[Test]
public void Edit_Get_ReturnsView()
{
//Arrange
CreateGroupFormModel group = new CreateGroupFormModel()
{
GroupId = 2,
GroupName = "Test",
Description = "test" };
GroupController controller = new GroupController();
var fake = groupService.GetGroup(2);
groupRepository.Setup(x => x.GetById(2)).Returns(fake);
Mapper.CreateMap<CreateGroupFormModel, Group>().ForAllMembers(opt => opt.Ignore());
Mapper.AssertConfigurationIsValid();
ViewResult actual = controller.EditGroup(2) as ViewResult;
Assert.IsNotNull(actual, "View Result is null");
}
can any one help me. the test fails as
Expected Not Null
actual Null
In your controller action you are calling var group = groupService.GetGroup(id); and it is not very clear where this groupService is coming from. In your unit test you must mock it. For this to be possible your GroupController must take this dependency as constructor injection.
Also in your unit test you seem to have declared some group variable which is never used.
For example:
public class GroupController: Controller
{
private readonly IGroupService groupService;
public GroupController(IGroupService groupService)
{
this.groupService = groupService;
}
public ActionResult EditGroup(int id)
{
var group = this.groupService.GetGroup(id);
CreateGroupFormModel editGroup = Mapper.Map<Group, CreateGroupFormModel>(group);
if (group == null)
{
return HttpNotFound();
}
return View("_EditGroup", editGroup);
}
}
and now in your unit test you could mock this group service and provide expectations on the result of the GetGroup method:
[Test]
public void Edit_Get_ReturnsView()
{
// arrange
var group = new CreateGroupFormModel
{
GroupId = 2,
GroupName ="Test",
Description ="test"
};
var groupServiceMock = new Mock<IGroupService>();
groupServiceMock.Setup(x => x.GetGroup(group.GroupId)).Returns(group);
var sut = new GroupController(groupServiceMock.Object);
Mapper.CreateMap<CreateGroupFormModel, Group>().ForAllMembers(opt => opt.Ignore());
Mapper.AssertConfigurationIsValid();
// act
var actual = sut.EditGroup(group.GroupId) as ViewResult;
// assert
Assert.IsNotNull(actual);
Assert.IsInstanceOfType(typeof(ViewResult), actual);
}

Resources