From 931a3cd809c8b07ee9d630ff1debc2a4969e9101 Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Mon, 19 May 2014 21:56:03 -0700 Subject: [PATCH] Added functional tests for MVC. Created a test project to hold functional tests, a basic application for test purposes under test\WebSites and added the first functional test to validate view rendering. --- Mvc.sln | 29 +++++++ global.json | 2 +- .../BasicTests.cs | 84 +++++++++++++++++++ .../HttpResponseHelpers.cs | 22 +++++ ...Microsoft.AspNet.Mvc.FunctionalTests.kproj | 38 +++++++++ .../ResourceHelpers.cs | 26 ++++++ .../TestApplicationEnvironment.cs | 44 ++++++++++ .../resources/BasicWebSite.Home.Index.html | 34 ++++++++ .../project.json | 22 +++++ test/WebSites/BasicWebSite/BasicWebSite.kproj | 41 +++++++++ .../Controllers/HomeController.cs | 12 +++ test/WebSites/BasicWebSite/Startup.cs | 26 ++++++ .../BasicWebSite/Views/Home/Index.cshtml | 8 ++ .../BasicWebSite/Views/Shared/Error.cshtml | 7 ++ .../BasicWebSite/Views/Shared/_Layout.cshtml | 30 +++++++ test/WebSites/BasicWebSite/project.json | 10 +++ 16 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/BasicTests.cs create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/HttpResponseHelpers.cs create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/ResourceHelpers.cs create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/TestApplicationEnvironment.cs create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/BasicWebSite.Home.Index.html create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/project.json create mode 100644 test/WebSites/BasicWebSite/BasicWebSite.kproj create mode 100644 test/WebSites/BasicWebSite/Controllers/HomeController.cs create mode 100644 test/WebSites/BasicWebSite/Startup.cs create mode 100644 test/WebSites/BasicWebSite/Views/Home/Index.cshtml create mode 100644 test/WebSites/BasicWebSite/Views/Shared/Error.cshtml create mode 100644 test/WebSites/BasicWebSite/Views/Shared/_Layout.cshtml create mode 100644 test/WebSites/BasicWebSite/project.json diff --git a/Mvc.sln b/Mvc.sln index 9df59e90f9..34dc993019 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -29,6 +29,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSample.Web", "samples\Mv EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Razor.Host", "src\Microsoft.AspNet.Mvc.Razor.Host\Microsoft.AspNet.Mvc.Razor.Host.kproj", "{520B3AA4-363A-497C-8C15-80423C5AFC85}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebSites", "WebSites", "{16703B76-C9F7-4C75-AE6C-53D92E308E3C}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.FunctionalTests", "test\Microsoft.AspNet.Mvc.FunctionalTests\Microsoft.AspNet.Mvc.FunctionalTests.kproj", "{323D0C04-B518-4A8F-8A8E-3546AD153D34}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "BasicWebSite", "test\WebSites\BasicWebSite\BasicWebSite.kproj", "{34DF1487-12C6-476C-BE0A-F31DF1939AE5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -139,6 +145,26 @@ Global {520B3AA4-363A-497C-8C15-80423C5AFC85}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {520B3AA4-363A-497C-8C15-80423C5AFC85}.Release|Mixed Platforms.Build.0 = Release|Any CPU {520B3AA4-363A-497C-8C15-80423C5AFC85}.Release|x86.ActiveCfg = Release|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Debug|Any CPU.Build.0 = Debug|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Debug|x86.ActiveCfg = Debug|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Release|Any CPU.ActiveCfg = Release|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Release|Any CPU.Build.0 = Release|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {323D0C04-B518-4A8F-8A8E-3546AD153D34}.Release|x86.ActiveCfg = Release|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Debug|x86.ActiveCfg = Debug|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Release|Any CPU.Build.0 = Release|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {34DF1487-12C6-476C-BE0A-F31DF1939AE5}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -154,5 +180,8 @@ Global {A8AA326E-8EE8-4F11-B750-23028E0949D7} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} {FBB2B86E-972B-4185-9FF2-62CAB5F8388F} = {DAAE4C74-D06F-4874-A166-33305D2643CE} {520B3AA4-363A-497C-8C15-80423C5AFC85} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} + {16703B76-C9F7-4C75-AE6C-53D92E308E3C} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} + {323D0C04-B518-4A8F-8A8E-3546AD153D34} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} + {34DF1487-12C6-476C-BE0A-F31DF1939AE5} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} EndGlobalSection EndGlobal diff --git a/global.json b/global.json index 840c36f6ad..b90c8282a0 100644 --- a/global.json +++ b/global.json @@ -1,3 +1,3 @@ { - "sources": ["src"] + "sources": ["src", "test\\WebSites"] } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/BasicTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/BasicTests.cs new file mode 100644 index 0000000000..a21d17826e --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/BasicTests.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Reflection; +using System.Threading.Tasks; +using BasicWebSite; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.TestHost; +using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.DependencyInjection.Fallback; +using Microsoft.Framework.Runtime; +using Microsoft.Framework.Runtime.Infrastructure; +using Xunit; + +namespace Microsoft.AspNet.Mvc.FunctionalTests +{ + public class BasicTests + { + private readonly IServiceProvider _provider; + private readonly Action _app = new Startup().Configure; + + // Some tests require comparing the actual response body against an expected response baseline + // so they require a reference to the assembly on which the resources are located, in order to + // make the tests less verbose, we get a reference to the assembly with the resources and we + // use it on all the rest of the tests. + private readonly Assembly _resourcesAssembly = typeof(BasicTests).GetTypeInfo().Assembly; + + public BasicTests() + { + var originalProvider = CallContextServiceLocator.Locator.ServiceProvider; + IApplicationEnvironment appEnvironment = originalProvider.GetService(); + + // When an application executes in a regular context, the application base path points to the root + // directory where the application is located, for example MvcSample.Web. However, when executing + // an aplication as part of a test, the ApplicationBasePath of the IApplicationEnvironment points + // to the root folder of the test project. + // To compensate for this, we need to calculate the original path and override the application + // environment value so that components like the view engine work properly in the context of the + // test. + string appBasePath = CalculateApplicationBasePath(appEnvironment); + _provider = new ServiceCollection() + .AddInstance(typeof(IApplicationEnvironment), new TestApplicationEnvironment(appEnvironment, appBasePath)) + .BuildServiceProvider(originalProvider); + } + + [Fact] + public async Task CanRender_ViewsWithLayout() + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + + // The K runtime compiles every file under compiler/resources as a resource at runtime with the same name + // as the file name, in order to update a baseline you just need to change the file in that folder. + var expectedContent = await _resourcesAssembly.ReadResourceAsStringAsync("BasicWebSite.Home.Index.html"); + + // Act + + // The host is not important as everything runs in memory and tests are isolated from each other. + var result = await client.GetAsync("http://localhost/"); + Assert.Equal(200, result.StatusCode); + Assert.Equal(result.ContentType, "text/html; charset=utf-8"); + var responseContent = await result.ReadBodyAsStringAsync(); + + // Assert + Assert.Equal(expectedContent, responseContent); + } + + // Calculate the path relative to the current application base path. + private static string CalculateApplicationBasePath(IApplicationEnvironment appEnvironment) + { + // Mvc/test/Microsoft.AspNet.Mvc.FunctionalTests + var appBase = appEnvironment.ApplicationBasePath; + + // Mvc/test + var test = Path.GetDirectoryName(appBase); + + // Mvc/test/WebSites/BasicWebSite + return Path.GetFullPath(Path.Combine(appBase, "..", "WebSites", "BasicWebSite")); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/HttpResponseHelpers.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/HttpResponseHelpers.cs new file mode 100644 index 0000000000..c2e77c4c0f --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/HttpResponseHelpers.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNet.Http; + +namespace Microsoft.AspNet.Mvc.FunctionalTests +{ + // This class contains methods to make easier to read responses in different formats + // until there is a built-in easier way to do it. + public static class HttpResponseHelpers + { + public static async Task ReadBodyAsStringAsync(this HttpResponse response) + { + using (var streamReader = new StreamReader(response.Body)) + { + return await streamReader.ReadToEndAsync(); + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj new file mode 100644 index 0000000000..ff8cf8805e --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj @@ -0,0 +1,38 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + Debug + AnyCPU + + + + 323d0c04-b518-4a8f-8a8e-3546ad153d34 + Library + + + ConsoleDebugger + + + WebDebugger + + + + + 2.0 + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ResourceHelpers.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ResourceHelpers.cs new file mode 100644 index 0000000000..b7b52ffd6b --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ResourceHelpers.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Reflection; +using System.Threading.Tasks; + +namespace Microsoft.AspNet.Mvc.FunctionalTests +{ + // This class contains helper methods for reading resources from a given assembly in order + // to make tests that require comparing against baseline files embedded as resources less + // verbose. + public static class ResourceHelpers + { + public static async Task ReadResourceAsStringAsync(this Assembly assembly, string resourceName) + { + using (var resourceStream = assembly.GetManifestResourceStream(resourceName)) + { + using (var streamReader = new StreamReader(resourceStream)) + { + return await streamReader.ReadToEndAsync(); + } + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/TestApplicationEnvironment.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/TestApplicationEnvironment.cs new file mode 100644 index 0000000000..b4849b5070 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/TestApplicationEnvironment.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.Versioning; +using Microsoft.Framework.Runtime; + +namespace Microsoft.AspNet.Mvc.FunctionalTests +{ + // Represents an application environment that overrides the base path of the original + // application environment in order to make it point to the folder of the original web + // aplication so that components like ViewEngines can find views as if they were executing + // in a regular context. + public class TestApplicationEnvironment : IApplicationEnvironment + { + private readonly IApplicationEnvironment _originalAppEnvironment; + private readonly string _applicationBasePath; + + public TestApplicationEnvironment(IApplicationEnvironment originalAppEnvironment, string appBasePath) + { + _originalAppEnvironment = originalAppEnvironment; + _applicationBasePath = appBasePath; + } + + public string ApplicationName + { + get { return _originalAppEnvironment.ApplicationName; } + } + + public string Version + { + get { return _originalAppEnvironment.Version; } + } + + public string ApplicationBasePath + { + get { return _applicationBasePath; } + } + + public FrameworkName TargetFramework + { + get { return _originalAppEnvironment.TargetFramework; } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/BasicWebSite.Home.Index.html b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/BasicWebSite.Home.Index.html new file mode 100644 index 0000000000..23fc107021 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/BasicWebSite.Home.Index.html @@ -0,0 +1,34 @@ + + + + + + Home Page - My ASP.NET Application + + + +
+
+ +
+ +
+
+
+
+ + +
+

ASP.NET vNext

+
+
+
+

© 2014 - My ASP.NET Application

+
+
+ + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json new file mode 100644 index 0000000000..de453d5f84 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json @@ -0,0 +1,22 @@ +{ + "version": "0.1-alpha-*", + "compilationOptions": { + "warningsAsErrors": true + }, + "dependencies": { + "BasicWebSite": "", + "Microsoft.AspNet.TestHost": "0.1-alpha-*", + "Microsoft.Framework.Runtime.Interfaces": "0.1-alpha-*", + "xunit.abstractions": "2.0.0-aspnet-*", + "xunit.assert": "2.0.0-aspnet-*", + "xunit.core": "2.0.0-aspnet-*", + "Xunit.KRunner": "0.1-alpha-*" + }, + "commands": { + "test": "Xunit.KRunner" + }, + "configurations": { + "net45": { }, + "k10": { } + } +} diff --git a/test/WebSites/BasicWebSite/BasicWebSite.kproj b/test/WebSites/BasicWebSite/BasicWebSite.kproj new file mode 100644 index 0000000000..3d70c1a8d3 --- /dev/null +++ b/test/WebSites/BasicWebSite/BasicWebSite.kproj @@ -0,0 +1,41 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + Debug + AnyCPU + + + + 34df1487-12c6-476c-be0a-f31df1939ae5 + Web + + + ConsoleDebugger + + + WebDebugger + + + + + 2.0 + + + 38820 + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/WebSites/BasicWebSite/Controllers/HomeController.cs b/test/WebSites/BasicWebSite/Controllers/HomeController.cs new file mode 100644 index 0000000000..1b9005ca49 --- /dev/null +++ b/test/WebSites/BasicWebSite/Controllers/HomeController.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNet.Mvc; + +namespace BasicWebSite.Controllers +{ + public class HomeController : Controller + { + public IActionResult Index() + { + return View(); + } + } +} \ No newline at end of file diff --git a/test/WebSites/BasicWebSite/Startup.cs b/test/WebSites/BasicWebSite/Startup.cs new file mode 100644 index 0000000000..667b0dc330 --- /dev/null +++ b/test/WebSites/BasicWebSite/Startup.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Routing; +using Microsoft.Framework.DependencyInjection; + +namespace BasicWebSite +{ + public class Startup + { + public void Configure(IBuilder app) + { + // Set up application services + app.UseServices(services => + { + // Add MVC services to the services container + services.AddMvc(); + }); + + // Add MVC to the request pipeline + app.UseMvc(routes => + { + routes.MapRoute("ActionAsMethod", "{controller}/{action}/{id?}", + defaults: new { controller = "Home", action = "Index" }); + }); + } + } +} diff --git a/test/WebSites/BasicWebSite/Views/Home/Index.cshtml b/test/WebSites/BasicWebSite/Views/Home/Index.cshtml new file mode 100644 index 0000000000..923887e69a --- /dev/null +++ b/test/WebSites/BasicWebSite/Views/Home/Index.cshtml @@ -0,0 +1,8 @@ +@{ + Layout = "/Views/Shared/_Layout.cshtml"; + ViewBag.Title = "Home Page"; +} + +
+

ASP.NET vNext

+
\ No newline at end of file diff --git a/test/WebSites/BasicWebSite/Views/Shared/Error.cshtml b/test/WebSites/BasicWebSite/Views/Shared/Error.cshtml new file mode 100644 index 0000000000..5d73bf597b --- /dev/null +++ b/test/WebSites/BasicWebSite/Views/Shared/Error.cshtml @@ -0,0 +1,7 @@ +@{ + Layout = "/Views/Shared/_Layout.cshtml"; + ViewBag.Title = "Error"; +} + +

Error.

+

An error occurred while processing your request.

\ No newline at end of file diff --git a/test/WebSites/BasicWebSite/Views/Shared/_Layout.cshtml b/test/WebSites/BasicWebSite/Views/Shared/_Layout.cshtml new file mode 100644 index 0000000000..48f6da692c --- /dev/null +++ b/test/WebSites/BasicWebSite/Views/Shared/_Layout.cshtml @@ -0,0 +1,30 @@ + + + + + + @ViewBag.Title - My ASP.NET Application + + + +
+
+
+ @Html.ActionLink("BasicWebApplication", "Index", "Home", new { area = "" }) +
+
+
    +
  • @Html.ActionLink("Home", "Index", "Home")
  • +
+
+
+
+
+ @RenderBody() +
+ +
+ + \ No newline at end of file diff --git a/test/WebSites/BasicWebSite/project.json b/test/WebSites/BasicWebSite/project.json new file mode 100644 index 0000000000..753f360c85 --- /dev/null +++ b/test/WebSites/BasicWebSite/project.json @@ -0,0 +1,10 @@ +{ + "dependencies": { + "Helios": "0.1-alpha-*", + "Microsoft.AspNet.Mvc": "" + }, + "configurations": { + "net45": { }, + "k10": { } + } +}