Testing WebSecurity.Login() problems - unit-testing

I'm trying to test my ASP.NET MVC4 Application within Visual Studio and I am running into problems when testing WebSecurity.Login().
It seems to work perfectly when running my application but throws out an error when testing.
Method to test:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(HomeModels.LoginModel model)
{
if (ModelState.IsValid)
{
try
{
var username = model.Username;
var password = model.Password;
if (WebSecurity.Login(username, password, true))
{
if (Roles.Provider.IsUserInRole(username, "admin"))
{
return RedirectToAction("AdminHome");
}
else if (Roles.Provider.IsUserInRole(username, "user"))
{
return RedirectToAction("LoginSuccessful");
}
}
else
{
//String errorMessage = "Login was not successful.";
}
}
catch (MemberAccessException e)
{
ModelState.AddModelError("", e);
}
}
return View(model);
}
Test Method:
[TestMethod]
public void TestLoginAdminSuccessfulView()
{
HomeController controller = new HomeController();
Ecommerce.Models.HomeModels.LoginModel login = new Ecommerce.Models.HomeModels.LoginModel();
login.Username = "sgupta";
login.Password = "sgupta2189";
var result = (RedirectToRouteResult) controller.Login(login);
Assert.AreEqual("AdminHome", result.RouteName);
}
Error Message:
Test method EcommerceUnitTests.Controllers.HomeControllerTest.TestLoginAdminSuccessfulView threw exception:
System.InvalidOperationException: To call this method, the "Membership.Provider" property must be an instance of "ExtendedMembershipProvider".
Error Stack Trace:
WebMatrix.WebData.WebSecurity.VerifyProvider()
WebMatrix.WebData.WebSecurity.Login(String userName, String password, Boolean persistCookie)
Ecommerce.Controllers.HomeController.Login(LoginModel model)
EcommerceUnitTests.Controllers.HomeControllerTest.TestLoginAdminSuccessfulView()

copy the working web.config to app.config in the project containing your tests.
Make sure your Test project references assembly that is / contains your custom member provider.
If the main project is working, check what references it has.

I ended up restructuring it all and using ASP.NET's default membership provider.

Related

Integrating ASP.NET Web Api and Android Volley

I'm developing an ASP.NET Web Api project with Entity Framework and other project with Android and the Volley lib.
The idea is the project in ASP.NET to be the server and the Android app the client.
Both projects already work. The ASP.NET project is already connected to SQL Server and returns values in json format from one database, and the client also parses json from an online server that I used for testing when I was following one tutorial.
ASP.NET Web Api Controller:
public class StoreController : ApiController
{
// GET: api/Store
public IEnumerable<bo> Get()
{
using (EGLA_PHCEntities services = new EGLA_PHCEntities())
{
return services.bo.Where(e => e.nmdos == "Ficha Servico 30").Where(e => e.fechada == false).ToList();
}
}
...
}
Android:
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray jsonArray = response.getJSONArray(null);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject employee = jsonArray.getJSONObject(i);
String firstName = employee.getString("fieldA");
String mail = employee.getString("fieldB");
mTextViewResult.append(firstName + ", " + mail + "\n\n");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
}
});
The problem is that my project in ASP.NET does not return a name for the array of objects, and Android is waiting for a name.
The solution can be applied in one side or another. It can go through the ASP.NET project to return a name, or the project in Android to parse the json with an empty array name.
Modified because the list of fields is very extense:
[
{
"fieldA":"Something",
"fieldB":"Store 30",
},
{
"fieldA":"Something 2",
"fieldB":"Store 30 2",
}
]
The error that is returned in the Android app is "org.json.JSONException: No value for null". If I change
JSONArray jsonArray = response.getJSONArray(null);
to:
JSONArray jsonArray = response.getJSONArray("services");
The error returned is: "org.json.JSONException: No value for services"

MvvmCross 5 Unit Test MvxNavigationService

I am updating from MvvmCross 4.4.0 to 5.2.0 and changing to the MvxNavigationService. The Login ViewModel was changed to use the MvxNavigationService and the IMvxNavigationService is registered for both the core and test. The iOS application is functioning correctly. The majority of the unit tests were fixed, but I'm having trouble with verifying the navigation completed correctly using unit test. The trace in the unit test also navigates correctly, but MockDispatcher.Requests is returning null. MockDispatcher.Requests should contain a value after viewModel.OnLoginAsync().Wait(); is called. How do I go about resolving this issue?
The unit test is
[Test]
public void OnLogin_GivenValidCredentials_ThenAppRedirectsToMainPage()
{
Mock<IAuthenticationService> authenticationService = GetAuthenticationService();
SetupCredentialValidity(authenticationService, true);
var viewModel = GetLoginViewModel(null, authenticationService);
viewModel.OnLoginAsync().Wait();
Assert.IsNull(viewModel.ErrorMessage);
Assert.AreEqual(1, MockDispatcher.Requests.Count, "Expected to navigate to the admin view model, but didn't");
Assert.AreEqual(typeof(HomeTabBarViewModel), MockDispatcher.Requests[0].ViewModelType);
}
For the method
public async Task OnLoginAsync()
{
IsActivityIndicatorVisible = true;
try
{
if (Username == MobileAdminUsername && Password == MobileAdminPassword)
{
await _mvxNavigationService.Navigate<AdminViewModel>();
//ShowViewModel<AdminViewModel>();
return;
}
var authenticateResult = await _authenticationService.Authenticate(Username, Password);
LoginResultsVisible = !authenticateResult.Success;
ErrorMessage = authenticateResult.Message;
if (authenticateResult.Success)
{
await _credentialCacheService.SetLastSuccessfulCredentials(Username, Password);
//ShowViewModel<HomeTabBarViewModel>();
await _mvxNavigationService.Navigate<HomeTabBarViewModel>();
}
}
finally
{
IsActivityIndicatorVisible = false;
}
}

How do I get my NancyFX unit tests to run my validation?

I'm using NancyFX with FluentValidation, as documented at https://github.com/NancyFx/Nancy/wiki/Nancy-and-Validation. My web app is running fine and validation is working perfectly, but when I try to unit test any of the modules that use validation, I'm getting an error
Nancy.Validation.ModelValidationException : No model validator factory could be located.
Please ensure that you have an appropriate validation package installed, such as
one of the Nancy.Validation packages.
I've verified that my unit test project has references to the Nancy.Validation.FluentValidation and FluentValidation assemblies.
My test code looks like this:
public class ArticleModuleTests {
private Browser browser;
private IDatabase db;
const int USER_ID = 123;
const int ARTICLE_ID = 456;
[SetUp]
public void SetUp() {
var user = new User { Username = "test", Id = USER_ID };
db = A.Fake<IDatabase>();
browser = new Browser(with => {
with.Module<ArticleModule>();
with.RequestStartup((container, pipelines, context) => context.CurrentUser = user);
with.Dependency(db);
});
}
[Test]
public void User_Can_Publish_Article() {
var article = new { title = "Test" };
var result = browser.Post($"/users/{USER_ID}/articles", with => {
with.HttpRequest();
with.Body(JsonConvert.SerializeObject(article));
});
result.StatusCode.ShouldBe(HttpStatusCode.BadRequest);
}
}
My module code is:
public class ArticlesModule : NancyModule {
private IDatabase database;
public ArticlesModule(IDatabase db) {
this.database = db;
Post["/users/{id:int}/articles"] = args => PostArticle(args.id);
}
private dynamic PostArticle(int userId) {
var article = this.Bind<Article>();
var validation = this.Validate(article);
if (!validation.IsValid) return Negotiate.WithModel(validation).WithStatusCode(HttpStatusCode.BadRequest);
database.CreateArticle(userId, article);
return NegotiatorExtensions.WithModel(Negotiate, result)
.WithStatusCode(HttpStatusCode.Created)
.WithHeader("Location", $"http://whatever/users/{userId}/articles/{article.Id}");
}
}
and my validation class is:
public class ArticleValidator : AbstractValidator<Article> {
public ArticleValidator() {
RuleFor(article => article.Title)
.NotEmpty()
.WithMessage("The \"title\" property is required");
RuleFor(article => article.Title)
.Length(2, 50)
.WithMessage("The \"title\" property must be between 2 and 50 characters");
}
}
The NancyFX docs say "Create a validation class... There is no need to register it anywhere as it is automatically detected." - but I'm guessing whatever automatic detection is wired up isn't firing for a unit test project. I'm building on .NET 4.5.2 and using NCrunch as my test runner; what do I need to do to get my test code to pick up the same validation classes as my application modules?
OK, turns out that because NancyFX detects and instantiates validation classes automatically, there's no explicit references in my code to Nancy.Validation.FluentValidation, and so NCrunch is omitting this assembly when building my test project. Setting "Copy referenced assemblies to workspace" in the NCrunch project settings fixed it.

How can i write unit test for this actionfilter

public MyContext _db;
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (_db == null || !_db.ChangeTracker.HasChanges())
{
return;
}
try
{
_db.SaveChanges();
}
catch
{
}
}
This is my action filter for my wep api project. _db context object injected to this filter by per request. My point is here to call SaveChanges() method once after all processing done in service layers. My problem is how can test this filter? How can i mimic exception case that can happen in any controler or service layer and when exception throws saveChanges() never called? How can i setup the case that exception occurred in any place inside application?
I have been doing the same, last week, for my WebAPI 2 action filter.
I have an action filter that validates my ModelState and in case of any error it throws an error list with 200 HTTPcode.
The action looks like this:
public class ModelValidationActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
{
actionContext.Response = ...
}
}
}
UNIT TEST
var httpControllerContext = new HttpControllerContext
{
Request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/someUri")
{
Content = new ObjectContent(typeof(MyModel),
new MyModel(), new JsonMediaTypeFormatter())
},
RequestContext = new HttpRequestContext()
};
httpControllerContext.Request = new HttpRequestMessage();
httpControllerContext.Request.SetConfiguration(new HttpConfiguration());
var httpActionContext = new HttpActionContext { ControllerContext = httpControllerContext };
var filter = new ModelValidationActionFilterAttribute();
httpActionContext.ModelState.AddModelError("*", "Invalid model state");
// act
filter.OnActionExecuting(httpActionContext);
// assert
httpActionContext.Response.ShouldNotBe(null);
httpActionContext.Response.ShouldBeOfType(typeof (HttpResponseMessage));
var result = httpActionContext.Response.Content.ReadAsStringAsync().Result;
BaseServiceResponse<object> resultResponse =
JsonConvert.DeserializeObject<BaseServiceResponse<object>>(result);
resultResponse.Data.ShouldBe(null);
resultResponse.Messages.Count.ShouldBe(1);
resultResponse.Messages.First().Description.ShouldBe("Invalid model state");
In your case you need to Mock DB context using IDbContext interface - see here: http://aikmeng.com/post/62817541825/how-to-mock-dbcontext-and-dbset-with-moq-for-unit
If an unhandled exception occurs while executing the request then the Exception property on actionExecutedContext will contain the exception. This is part of the framework, and not something you need to test. In your tests you can simple set the Exception property manually and assert that the attribute takes the correct action.
[Fact]
public void Saves_data_on_failure()
{
var mockDbContext = new Mock<IDbContext>();
var myAttribute = new MyAttribute(mockDbContext.Object);
var executionContext = new HttpActionExecutedContext
{
Exception = new Exception("Request failed.")
};
myAttribute.OnActionExecuted(executionContext);
mockDbContext.Verify(d => d.SaveChanges());
}
You might also want to consider whether or not you want to save data for all types of exception. The data might be in an invalid/unknown state.

Unit Testing MVC 4 RedirectToAction

I am trying to unit test the redirection of my controller in MVC 4 .Net 4.5. Here is an example:
[TestMethod]
public void Register_PassValidModel_RedirectToHomeIndexShouldBeTrue()
{
//Arrange
var registerModel = new RegisterModel
{
Email = "validEmailAddress#domain.com",
Password = "password"
};
//Assign
var result = _controller.Register(registerModel) as RedirectToRouteResult;
//Assert
result.RouteValues["Action"].ShouldBeEqual("Index");
result.RouteValues["Controller"].ShouldBeEqual("Home");
}
Here is the controller:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
var userToRegister = new User { Email = model.Email, Password = model.Password };
var service = new UserService(_userRepository);
User user = service.RegisterUser(userToRegister);
if (user.UserErrorMessages.Count != 0)
{
user.UserErrorMessages.ForEach(x => ModelState.AddModelError("", x));
return View(model);
}
SetCookie(model.Email);
return RedirectToAction("Index", "Home");
}
return View(model);
}
The issue the variable result in the Unit Test is null. I found this code from someone who was working on a MVC 2 project and it seemed to work for him. Has something changed with MVC 4?
Thanks in advance!
Try this one hope it will useful for you
var result= (RedirectToRouteResult)controller.Register(registrModel);
result.RouteValues["action"].Equals("Index");
result.RouteValues["controller"].Equals("Home");
Assert.AreEqual("Index", action.RouteValues["action"]);
Assert.AreEqual("Home", action.RouteValues["controller"]);