MyTested.AspNetCore.Mvc is a unit testing library providing easy fluent interface to test the ASP.NET Core MVC framework. It is testing framework agnostic, so you can combine it with a test runner of your choice (e.g. xUnit, NUnit, etc.).
It is strongly advised to start with the tutorial (coming soon) in order to get familiar with MyTested.AspNetCore.Mvc. Additionally, you may see the testing guide (coming soon) or the API reference for full list of available features. MyTested.AspNetCore.Mvc is 100% covered by more than 1800 unit tests and should work correctly. Almost all items in the issues page are expected future features and enhancements.
You can install this library using NuGet into your test project (or reference it directly in your project.json
file). Currently MyTested.AspNetCore.Mvc works with ASP.NET Core MVC 1.0.1.
Install-Package MyTested.AspNetCore.Mvc.Universe
This package will include all available assertion methods in your test project, including ones for authentication, database, session, caching and more. If you want only the MVC related features, install MyTested.AspNetCore.Mvc
. If you want to use the completely FREE and UNLIMITED version of the library, install only MyTested.AspNetCore.Mvc.Lite
and no other package. Additionally, if you prefer, you can be more specific by including only some of the packages:
MyTested.AspNetCore.Mvc.Controllers
- Contains setup and assertion methods for controllersMyTested.AspNetCore.Mvc.Models
- Contains setup and assertion methods for response and view modelsMyTested.AspNetCore.Mvc.Routing
- Contains setup and assertion methods for routesMyTested.AspNetCore.Mvc.Core
- Contains setup and assertion methods for MVC core featuresMyTested.AspNetCore.Mvc.TempData
- Contains setup and assertion methods forITempDataDictionary
MyTested.AspNetCore.Mvc.ViewData
- Contains assertion methods forViewDataDictionary
and dynamicViewBag
MyTested.AspNetCore.Mvc.ViewActionResults
- Contains setup and assertion methods for view action resultsMyTested.AspNetCore.Mvc.ViewComponents
- Contains setup and assertion methods for view componentsMyTested.AspNetCore.Mvc.ViewFeatures
- Contains setup and assertion methods for MVC view featuresMyTested.AspNetCore.Mvc.Http
- Contains setup and assertion methods for HTTP context, request and responseMyTested.AspNetCore.Mvc.Authentication
- Contains setup methods forClaimsPrincipal
MyTested.AspNetCore.Mvc.ModelState
- Contains setup and assertion methods forModelStateDictionary
validationsMyTested.AspNetCore.Mvc.DataAnnotations
- Contains setup and assertion methods for data annotation validationsMyTested.AspNetCore.Mvc.EntityFrameworkCore
- Contains setup and assertion methods forDbContext
MyTested.AspNetCore.Mvc.DependencyInjection
- Contains setup methods for dependency injection servicesMyTested.AspNetCore.Mvc.Caching
- Contains setup and assertion methods forIMemoryCache
MyTested.AspNetCore.Mvc.Session
- Contains setup and assertion methods forISession
MyTested.AspNetCore.Mvc.Options
- Contains setup and assertion methods forIOptions
MyTested.AspNetCore.Mvc.Helpers
- Contains additional helper methods for easier assertionsMyTested.AspNetCore.Mvc.Lite
- Completely FREE and UNLIMITED version of the library. It should not be used in combination with any other package. IncludesControllers
,ViewActionResults
andViewComponents
.
After the downloading is complete, just add using MyTested.AspNetCore.Mvc;
to your source code and you are ready to test in the most elegant and developer friendly way.
using MyTested.AspNetCore.Mvc;
For other interesting packages check out:
- MyTested.WebApi - fluent testing framework for ASP.NET Web API 2
- MyTested.HttpServer - fluent testing framework for remote HTTP servers
- AspNet.Mvc.TypedRouting - typed routing and link generation for ASP.NET Core MVC
- ASP.NET MVC 5 Lambda Expression Helpers - typed expression based link generation for ASP.NET MVC 5
Make sure to check out the tutorial (coming soon) and the testing guide (coming soon) for a preview of the available features.
You can also check out the provided samples for real-life ASP.NET Core MVC application testing.
The easiest way to start with MyTested.AspNetCore.Mvc is to create a TestStartup
class at the root of the test project in order to register the dependency injection services which will be used by all test cases in the assembly. A fast solution is to inherit from the web project's Startup
class and replace some of the services with mocked ones by using the provided extension methods.
namespace MyApp.Tests
{
using MyTested.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
public class TestStartup : Startup
{
public void ConfigureTestServices(IServiceCollection services)
{
base.ConfigureServices(services);
services.Replace<IService, MockedService>();
}
}
}
And then you can create a test case by using the fluent API the library provides. You are given a static MyMvc
class from which all assertions can be easily configured.
namespace MyApp.Tests.Controllers
{
using MyTested.AspNetCore.Mvc;
using MyApp.Controllers;
using Xunit;
public class HomeControllerShould
{
[Fact]
public void ReturnViewWhenCallingIndexAction()
{
MyMvc
.Controller<HomeController>()
.Calling(c => c.Index())
.ShouldReturn()
.View();
}
}
}
Basically, MyTested.AspNetCore.Mvc throws an unhandled exception with a friendly error message if the assertion does not pass and the test fails. The example uses xUnit but you can use any other framework you like. See the samples for other types of test runners and Startup
class configurations.
Here are some random examples of what the fluent testing API is capable of:
// tests a route for correct controller, action and resolved route values
MyMvc
.Routing()
.ShouldMap(request => request
.WithLocation("/My/Action/1")
.WithMethod(HttpMethod.Post)
.WithAuthenticatedUser()
.WithAntiForgeryToken()
.WithJsonBody(new
{
Integer = 1,
String = "Text"
}))
.To<MyController>(c => c.Action(1, new MyModel
{
Integer = 1,
String = "Text"
}))
.AndAlso()
.ToValidModelState();
// instantiates controller with the registered services
// and mocks authenticated user
// and tests for valid model state
// and tests for valid view bag entry
// and tests model from view result with specific assertions
MyMvc
.Controller<MvcController>()
.WithAuthenticatedUser(user => user.WithUsername("MyUserName"))
.Calling(c => c.SomeAction(requestModel))
.ShouldHave()
.ValidModelState()
.AndAlso()
.ShouldHave()
.ViewBag(viewBag => viewBag
.ContainingEntry("MyViewBagProperty", "MyViewBagValue"))
.AndAlso()
.ShouldReturn()
.View()
.WithModelOfType<ResponseModel>()
.Passing(m =>
{
Assert.AreEqual(1, m.Id);
Assert.AreEqual("Some property value", m.SomeProperty);
});
// instantiates controller with the registered services
// and sets options for the current test
// and sets session for the current test
// and sets DbContext for the current test
// and tests for added cache entry by the action
// and tests model from view result
MyMvc
.Controller<MvcController>()
.WithOptions(options => options
.For<AppSettings>(settings => settings.Cache = true))
.WithSession(session => session
.WithEntry("Session", "SessionValue"))
.WithDbContext(db => db.WithEntities(entities => entities
.AddRange(SampleDataProvider.GetModels())))
.Calling(c => c.SomeAction())
.ShouldHave()
.MemoryCache(cache => cache
.ContainingEntry(entry => entry
.WithKey("CacheEntry")
.WithSlidingExpiration(TimeSpan.FromMinutes(10))
.WithValueOfType<CachedModel>()
.Passing(a => a.Id == 1)))
.AndAlso()
.ShouldReturn()
.View()
.WithModelOfType<ResponseModel>();
// tests whether the action is declared with filters
MyMvc
.Controller<MvcController>()
.Calling(c => c.MyAction())
.ShouldHave()
.ActionAttributes(attributes => attributes
.RestrictingForHttpMethod(HttpMethod.Get)
.AllowingAnonymousRequests()
.ValidatingAntiForgeryToken()
.ChangingActionNameTo("AnotherAction"));
// tests whether model state error exists by using lambda expression
// and with specific tests for the error messages
// and tests whether the action return view with the same request model
MyMvc
.Controller<MvcController>()
.Calling(c => c.MyAction(requestWithErrors))
.ShouldHave()
.ModelState(modelState => modelState.For<RequestModel>()
.ContainingNoErrorFor(m => m.NonRequiredProperty)
.AndAlso()
.ContainingErrorFor(m => m.RequiredProperty)
.ThatEquals("The RequiredProperty field is required."))
.AndAlso()
.ShouldReturn()
.View(requestWithErrors);
// tests whether the action throws
// with exception of certain type and with certain message
MyMvc
.Controller<MvcController>()
.Calling(c => c.ActionWithException())
.ShouldThrow()
.Exception()
.OfType<NullReferenceException>()
.AndAlso()
.WithMessage().ThatEquals("Test exception message");
// all applicable methods are available
// on view component testing too
MyMvc
.ViewComponent<MvcComponent>()
.WithSession(session => session
.WithEntry("Session", "SessionValue"))
.WithDbContext(db => db.WithEntities(entities => entities
.AddRange(SampleDataProvider.GetModels())))
.InvokedWith(c => c.InvokeAsync(1))
.ShouldHave()
.ViewBag(viewBag => viewBag
.ContainingEntry("TotalItems", 10)
.ContainingEntry("EntryName", "ViewBagName"))
.AndAlso()
.ShouldReturn()
.View()
.WithModelOfType<ResponseModel>();
Code by Ivaylo Kenov. Copyright 2015-2016 Ivaylo Kenov (http://mytestedasp.net)
MyTested.AspNetCore.Mvc.Lite (the FREE and UNLIMITED version of the testing library) is dual-licensed under either the Apache License, Version 2.0, or the Microsoft Public License (Ms-PL).
The source code of MyTested.AspNetCore.Mvc and its extensions (the full version of the testing library) is available under GNU Affero General Public License/FOSS License Exception.
Without a license code the full version of the library allows up to 100 assertions (around 25 test cases) per test project.
Full-featured license codes can be requested for free by individuals, open-source projects, startups and educational institutions. See https://mytestedasp.net/Core/Mvc#free-usage-modal for more information.
Commercial licensing with private support is also available at https://mytestedasp.net/Core/Mvc#pricing.
See the LICENSE for detailed information.
If you have a feature request or bug report, leave an issue on the issues page or send a pull request. For general questions and comments, use the StackOverflow forum.