{"id":12465,"date":"2018-03-05T10:30:28","date_gmt":"2018-03-05T18:30:28","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=12465"},"modified":"2018-03-05T10:30:28","modified_gmt":"2018-03-05T18:30:28","slug":"asp-net-core-2-1-0-preview1-functional-testing-of-mvc-applications","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-2-1-0-preview1-functional-testing-of-mvc-applications\/","title":{"rendered":"ASP.NET Core 2.1.0-preview1: Functional testing of MVC applications"},"content":{"rendered":"<p>For ASP.NET Core 2.1 we have created a new package, <a href=\"https:\/\/nuget.org\/packages\/Microsoft.AspNetCore.Mvc.Testing\">Microsoft.AspNetCore.Mvc.Testing<\/a>, to help streamline in-memory end-to-end testing of MVC applications using <code>TestServer<\/code>.<\/p>\n<p>This package takes care of some of the typical <a href=\"https:\/\/blogs.msdn.microsoft.com\/webdev\/2017\/12\/07\/testing-asp-net-core-mvc-web-apps-in-memory\/\">pitfalls when trying to test MVC applications using TestServer<\/a>.<\/p>\n<ul>\n<li>It copies the .deps file from your project into the test assembly bin folder.<\/li>\n<li>It sets the content root the application&#039;s project root so that static files and views can be found.<\/li>\n<li>It provides a class <code>WebApplicationTestFixture&lt;TStartup&gt;<\/code> that streamlines the bootstrapping of your app on <code>TestServer<\/code>.<\/li>\n<\/ul>\n<h3 id=\"create-a-test-project\">Create a test project<\/h3>\n<p>To try out the new MVC test fixture, let&#039;s create an app and write an end-to-end in-memory test for the app.<\/p>\n<p>First, create an app to test.<\/p>\n<pre><code>dotnet <span class=\"hljs-keyword\">new<\/span> razor -au Individual -o TestingMvc<span class=\"hljs-regexp\">\/src\/<\/span>TestingMvc\n<\/code><\/pre>\n<p>Add an <a href=\"https:\/\/xunit.github.io\/\">xUnit<\/a> based test project.<\/p>\n<pre><code>dotnet <span class=\"hljs-keyword\">new<\/span> xunit -o TestingMvc<span class=\"hljs-regexp\">\/test\/<\/span>TestingMvc.Tests\n<\/code><\/pre>\n<p>Create a solution file and add the projects to the solution.<\/p>\n<pre><code>cd TestingMvc\ndotnet new sln\ndotnet sln <span class=\"hljs-keyword\">add<\/span><span class=\"bash\"> src\/TestingMvc\/TestingMvc.csproj\n<\/span>dotnet sln <span class=\"hljs-keyword\">add<\/span><span class=\"bash\"> <span class=\"hljs-built_in\">test<\/span>\/TestingMvc.Tests\/TestingMvc.Tests.csproj<\/span>\n<\/code><\/pre>\n<p>Add a reference from the test project to the app we&#039;re going to test.<\/p>\n<pre><code>dotnet <span class=\"hljs-keyword\">add<\/span><span class=\"bash\"> <span class=\"hljs-built_in\">test<\/span>\/TestingMvc.Tests\/TestingMvc.Tests.csproj reference src\/TestingMvc\/TestingMvc.csproj<\/span>\n<\/code><\/pre>\n<p>Add a reference to the Microsoft.AspNetCore.Mvc.Testing package.<\/p>\n<pre><code>dotnet add test\/TestingMvc.Tests\/TestingMvc<span class=\"hljs-selector-class\">.Tests<\/span><span class=\"hljs-selector-class\">.csproj<\/span> package Microsoft<span class=\"hljs-selector-class\">.AspNetCore<\/span><span class=\"hljs-selector-class\">.Mvc<\/span><span class=\"hljs-selector-class\">.Testing<\/span> -v <span class=\"hljs-number\">2.1<\/span>.<span class=\"hljs-number\">0<\/span>-preview1-final\n<\/code><\/pre>\n<p>In the test project create a test using the <code>WebApplicationTestFixture&lt;TStartup&gt;<\/code> class that retrieves the home page for the app. Use the test fixture create an <code>HttpClient<\/code> that allows you to invoke your app in-memory. <\/p>\n<pre><code class=\"lang-csharp\"><span class=\"hljs-keyword\">using<\/span> Xunit;\n\n<span class=\"hljs-keyword\">namespace<\/span> TestingMvc.Tests\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> TestingMvcFunctionalTests : IClassFixture&lt;WebApplicationTestFixture&lt;Startup&gt;&gt;\n    {\n        <span class=\"hljs-keyword\">public<\/span> TestingMvcFunctionalTests(WebApplicationTestFixture&lt;Startup&gt; fixture)\n        {\n            <span class=\"hljs-built_in\">Client<\/span> = fixture.CreateClient();\n        }\n\n        <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-built_in\">HttpClient<\/span> <span class=\"hljs-built_in\">Client<\/span> { <span class=\"hljs-built_in\">get<\/span>; }\n\n        [Fact]\n        <span class=\"hljs-keyword\">public<\/span> async <span class=\"hljs-built_in\">Task<\/span> GetHomePage()\n        {\n            <span class=\"hljs-comment\">\/\/ Arrange &amp; Act<\/span>\n            var response = await <span class=\"hljs-built_in\">Client<\/span>.GetAsync(<span class=\"hljs-string\">\"\/\"<\/span>);\n\n            <span class=\"hljs-comment\">\/\/ Assert<\/span>\n            Assert.Equal(HttpStatusCode.OK, response.StatusCode);\n        }\n    }\n}\n<\/code><\/pre>\n<p>To correctly invoke your app the test fixture tries to find a static method on the entry point class (typically <code>Program<\/code>) of the assembly containing the <code>Startup<\/code> class with the following signature:<\/p>\n<pre><code class=\"lang-c#\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> IWebHostBuilder <span class=\"hljs-title\">CreateWebHostBuilder<\/span><span class=\"hljs-params\">(<span class=\"hljs-built_in\">string<\/span> [] args)<\/span><\/span>\n<\/code><\/pre>\n<p>Fortunately the built-in project templates are already setup this way:<\/p>\n<pre><code class=\"lang-c#\"><span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">TestingMvc<\/span>\n{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Program<\/span>\n    {\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">Main<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">string<\/span>[] args<\/span>)\n        <\/span>{\n            CreateWebHostBuilder(args).Build().Run();\n        }\n\n        <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> IWebHostBuilder <span class=\"hljs-title\">CreateWebHostBuilder<\/span>(<span class=\"hljs-params\"><span class=\"hljs-keyword\">string<\/span>[] args<\/span>) <\/span>=&gt;\n            WebHost.CreateDefaultBuilder(args)\n                .UseStartup&lt;Startup&gt;();\n    }\n}\n<\/code><\/pre>\n<p>If you don&#039;t have the <code>Program.CreateWebHostBuilder<\/code> method the text fixture won&#039;t be able to initialize your app correctly for testing. Instead you can configure the <code>WebHostBuilder<\/code> yourself by overriding <code>CreateWebHostBuilder<\/code> on <code>WebApplicationTestFixture&lt;TStartup&gt;<\/code>.<\/p>\n<h3 id=\"specifying-the-app-content-root\">Specifying the app content root<\/h3>\n<p>The test fixture will also attempt to guess the content root of the app under test. By convention the test fixture assumes the app content root is at <code>&lt;&lt;SolutionFolder&gt;&gt;\/&lt;&lt;AppAssemblyName&gt;&gt;<\/code>. For example, based on the folder structure defined below, the content root of the application is defined as <code>\/work\/MyApp<\/code>.<\/p>\n<pre><code>\/work\n    \/MyApp<span class=\"hljs-selector-class\">.sln<\/span>\n    \/MyApp\/MyApp<span class=\"hljs-selector-class\">.csproj<\/span>\n    \/MyApp.Tests\/MyApp<span class=\"hljs-selector-class\">.Tests<\/span><span class=\"hljs-selector-class\">.csproj<\/span>\n<\/code><\/pre>\n<p>Because we are using a different layout for our projects we need to inherit from <code>WebApplicationTestFixture<\/code> and pass in the relative path from the solution to the app under test when calling the base constructor. In a future preview we plan to make configuration of the content root unnecessary, but for now this explicit configuration is required for our solution layout.<\/p>\n<pre><code class=\"lang-c#\">public <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">TestingMvcTestFixture<\/span>&lt;TStartup&gt; : <span class=\"hljs-title\">WebApplicationTestFixture<\/span>&lt;TStartup&gt; <span class=\"hljs-title\">where<\/span> <span class=\"hljs-title\">TStartup<\/span> : <span class=\"hljs-title\">class<\/span><\/span>\n{\n    public TestingMvcTestFixture()\n        : base(<span class=\"hljs-string\">\"src\/TestingMvc\"<\/span>) { }\n}\n<\/code><\/pre>\n<p>Update the test class to use the derived test fixture.<\/p>\n<pre><code class=\"lang-c#\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">class<\/span> TestingMvcFunctionalTests : IClassFixture&lt;TestingMvcTestFixture&lt;Startup&gt;&gt;\n{\n    <span class=\"hljs-keyword\">public<\/span> TestingMvcFunctionalTests(TestingMvcTestFixture&lt;Startup&gt; fixture)\n    {\n        <span class=\"hljs-built_in\">Client<\/span> = fixture.CreateClient();\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-built_in\">HttpClient<\/span> <span class=\"hljs-built_in\">Client<\/span> { <span class=\"hljs-built_in\">get<\/span>; }\n\n    [Fact]\n    <span class=\"hljs-keyword\">public<\/span> async <span class=\"hljs-built_in\">Task<\/span> GetHomePage()\n    {\n        <span class=\"hljs-comment\">\/\/ Arrange &amp; Act<\/span>\n        var response = await <span class=\"hljs-built_in\">Client<\/span>.GetAsync(<span class=\"hljs-string\">\"\/\"<\/span>);\n\n        <span class=\"hljs-comment\">\/\/ Assert<\/span>\n        Assert.Equal(HttpStatusCode.OK, response.StatusCode);\n    }\n}\n<\/code><\/pre>\n<p>For some end-to-end in-memory tests to work properly, shadow copying needs to be disabled in your test framework of choice, as it causes the tests to execute in a different folder than the output folder. For instructions on how to do this with xUnit see <a href=\"https:\/\/xunit.github.io\/docs\/configuring-with-json.html\">https:\/\/xunit.github.io\/docs\/configuring-with-json.html<\/a>.<\/p>\n<h3 id=\"run-the-test\">Run the test<\/h3>\n<p>Run the test by running <code>dotnet test<\/code> from the <code>TestingMvc.Tests<\/code> project directory. It should fail because the HTTP response is a temporary redirect instead of a 200 OK. This is because the app has HTTPS redirection middleware in its pipeline (see <a href=\"https:\/\/blogs.msdn.microsoft.com\/webdev\/2018\/02\/27\/asp-net-core-2-1-https-improvements\/\">Improvements for using HTTPS<\/a>) and base address setup by the test fixture is an HTTP address (&quot;<a href=\"http:\/\/localhost\">http:\/\/localhost<\/a>&quot;). The <code>HttpClient<\/code> by default doesn&#039;t follow these redirects. In a future preview we will update the text fixture to configure the <code>HttpClient<\/code> to follow redirects and also handle cookies. But at least now we know the test is successfully running the app&#039;s pipeline.<\/p>\n<p>This test was intended to make simple GET request to the app&#039;s home, not test the HTTPS redirect logic, so let&#039;s use the fixture to create an <code>HttpClient<\/code> that uses an HTTPS base address instead.<\/p>\n<pre><code class=\"lang-c#\"><span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-title\">TestingMvcFunctionalTests<\/span><span class=\"hljs-params\">(TestingMvcTestFixture&lt;Startup&gt; fixture)<\/span>\n<\/span>{\n    Client = fixture.CreateClient(<span class=\"hljs-keyword\">new<\/span> Uri(<span class=\"hljs-string\">\"https:\/\/localhost\"<\/span>));\n}\n<\/code><\/pre>\n<p>Rerun the test and it should now pass.<\/p>\n<pre><code>Starting test execution, please wait...\n[xUnit<span class=\"hljs-selector-class\">.net<\/span> <span class=\"hljs-number\">00<\/span>:<span class=\"hljs-number\">00<\/span>:<span class=\"hljs-number\">01.1767971<\/span>]   Discovering: TestingMvc<span class=\"hljs-selector-class\">.Tests<\/span>\n[xUnit<span class=\"hljs-selector-class\">.net<\/span> <span class=\"hljs-number\">00<\/span>:<span class=\"hljs-number\">00<\/span>:<span class=\"hljs-number\">01.2466823<\/span>]   Discovered:  TestingMvc<span class=\"hljs-selector-class\">.Tests<\/span>\n[xUnit<span class=\"hljs-selector-class\">.net<\/span> <span class=\"hljs-number\">00<\/span>:<span class=\"hljs-number\">00<\/span>:<span class=\"hljs-number\">01.2543165<\/span>]   Starting:    TestingMvc<span class=\"hljs-selector-class\">.Tests<\/span>\n[xUnit<span class=\"hljs-selector-class\">.net<\/span> <span class=\"hljs-number\">00<\/span>:<span class=\"hljs-number\">00<\/span>:<span class=\"hljs-number\">09.3860248<\/span>]   Finished:    TestingMvc<span class=\"hljs-selector-class\">.Tests<\/span>\n\nTotal tests: <span class=\"hljs-number\">1<\/span>. Passed: <span class=\"hljs-number\">1<\/span>. Failed: <span class=\"hljs-number\">0<\/span>. Skipped: <span class=\"hljs-number\">0<\/span>.\nTest Run Successful.\n<\/code><\/pre>\n<h3 id=\"summary\">Summary<\/h3>\n<p>We hope the new MVC test fixture in ASP.NET Core 2.1 will make it easier to reliably test your MVC applications. Please give it a try and let us know what you think on <a href=\"https:\/\/github.com\/aspnet\/mvc\/issues\">GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For ASP.NET Core 2.1 we have created a new package, Microsoft.AspNetCore.Mvc.Testing, to help streamline in-memory end-to-end testing of MVC applications using TestServer. This package takes care of some of the typical pitfalls when trying to test MVC applications using TestServer. It copies the .deps file from your project into the test assembly bin folder. It [&hellip;]<\/p>\n","protected":false},"author":417,"featured_media":21409,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197,7509],"tags":[7542,7551],"class_list":["post-12465","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-aspnetcore","tag-asp-net-core-2-1-0-preview1","tag-mvc-applications"],"acf":[],"blog_post_summary":"<p>For ASP.NET Core 2.1 we have created a new package, Microsoft.AspNetCore.Mvc.Testing, to help streamline in-memory end-to-end testing of MVC applications using TestServer. This package takes care of some of the typical pitfalls when trying to test MVC applications using TestServer. It copies the .deps file from your project into the test assembly bin folder. It [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/12465","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/417"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=12465"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/12465\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/21409"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=12465"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=12465"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=12465"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}