├── .gitignore ├── BREAKING_CHANGES.md ├── LICENSE.txt ├── NextVersion.txt ├── README.md ├── Samples ├── TestStack.FluentMVCTesting.Sample.Tests │ ├── Controllers │ │ └── ProductControllerTests.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── TestStack.FluentMVCTesting.Sample.Tests.csproj │ ├── app.config │ └── packages.config └── TestStack.FluentMVCTesting.Sample │ ├── App_Start │ ├── BundleConfig.cs │ ├── FilterConfig.cs │ ├── IdentityConfig.cs │ ├── RouteConfig.cs │ └── Startup.Auth.cs │ ├── Content │ ├── Site.css │ ├── bootstrap.css │ └── bootstrap.min.css │ ├── Controllers │ ├── AccountController.cs │ ├── HomeController.cs │ └── ProductController.cs │ ├── Global.asax │ ├── Global.asax.cs │ ├── Models │ ├── AccountViewModels.cs │ └── IdentityModels.cs │ ├── Project_Readme.html │ ├── Properties │ └── AssemblyInfo.cs │ ├── Scripts │ ├── _references.js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-1.10.2.intellisense.js │ ├── jquery-1.10.2.js │ ├── jquery-1.10.2.min.js │ ├── jquery-1.10.2.min.map │ ├── jquery.validate-vsdoc.js │ ├── jquery.validate.js │ ├── jquery.validate.min.js │ ├── jquery.validate.unobtrusive.js │ ├── jquery.validate.unobtrusive.min.js │ ├── modernizr-2.6.2.js │ ├── respond.js │ └── respond.min.js │ ├── Startup.cs │ ├── TestStack.FluentMVCTesting.Sample.csproj │ ├── Views │ ├── Account │ │ ├── ConfirmEmail.cshtml │ │ ├── ExternalLoginConfirmation.cshtml │ │ ├── ExternalLoginFailure.cshtml │ │ ├── ForgotPassword.cshtml │ │ ├── ForgotPasswordConfirmation.cshtml │ │ ├── Login.cshtml │ │ ├── Manage.cshtml │ │ ├── Register.cshtml │ │ ├── ResetPassword.cshtml │ │ ├── ResetPasswordConfirmation.cshtml │ │ ├── _ChangePasswordPartial.cshtml │ │ ├── _ExternalLoginsListPartial.cshtml │ │ ├── _RemoveAccountPartial.cshtml │ │ └── _SetPasswordPartial.cshtml │ ├── Home │ │ ├── About.cshtml │ │ ├── Contact.cshtml │ │ └── Index.cshtml │ ├── Product │ │ └── Product.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── _Layout.cshtml │ │ └── _LoginPartial.cshtml │ ├── Web.config │ └── _ViewStart.cshtml │ ├── Web.Debug.config │ ├── Web.Release.config │ ├── Web.config │ ├── favicon.ico │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff │ └── packages.config ├── TestStack.FluentMVCTesting.Mvc3.Tests ├── Properties │ └── AssemblyInfo.cs ├── TestStack.FluentMVCTesting.Mvc3.Tests.csproj └── packages.config ├── TestStack.FluentMVCTesting.Mvc3 ├── TestStack.FluentMVCTesting.Mvc3.csproj ├── TestStack.FluentMVCTesting.Mvc3.nuspec └── packages.config ├── TestStack.FluentMVCTesting.Mvc4.Tests ├── TestStack.FluentMVCTesting.Mvc4.Tests.csproj └── packages.config ├── TestStack.FluentMVCTesting.Mvc4 ├── TestStack.FluentMVCTesting.Mvc4.csproj ├── TestStack.FluentMVCTesting.Mvc4.nuspec └── packages.config ├── TestStack.FluentMVCTesting.Tests ├── AsyncControllerTests.cs ├── ControllerExtensionsTests.cs ├── ControllerResultTestTests │ ├── ControllerResultTestTests.cs │ ├── ShouldGiveHttpStatusTests.cs │ ├── ShouldRedirectToTests.cs │ ├── ShouldRenderFileTests.cs │ ├── ShouldRenderViewTests.cs │ ├── ShouldReturnContentTests.cs │ ├── ShouldReturnEmptyResultTests.cs │ └── ShouldReturnJsonTests.cs ├── ModelErrorTestTests.cs ├── ModelTestTests.cs ├── Properties │ └── AssemblyInfo.cs ├── RouteValueDictionaryExtensionsTests.cs ├── TempDataResultTest.cs ├── TestControllers │ ├── AsyncController.cs │ ├── ControllerExtensionsController.cs │ └── ControllerResultTestController.cs ├── TestStack.FluentMVCTesting.Tests.csproj ├── TestStack.FluentMVCTesting.Tests.csproj.DotSettings ├── ViewResultTestTests.cs └── packages.config ├── TestStack.FluentMVCTesting.sln ├── TestStack.FluentMvcTesting ├── App_Packages │ └── ExpressionStringBuilder.0.9.2 │ │ └── ExpressionStringBuilder.cs ├── ControllerExtensions.cs ├── ControllerResultTest │ ├── ControllerResultTest.cs │ ├── ShouldGiveHttpStatus.cs │ ├── ShouldRedirectTo.cs │ ├── ShouldRenderFile.cs │ ├── ShouldRenderView.cs │ ├── ShouldReturnContent.cs │ ├── ShouldReturnEmptyResult.cs │ └── ShouldReturnJson.cs ├── Exceptions.cs ├── ModelErrorTest.cs ├── ModelTest.cs ├── Properties │ └── AssemblyInfo.cs ├── RouteValueDictionaryExtension.cs ├── TempDataResultTest.cs ├── TestStack.FluentMVCTesting.csproj ├── TestStack.FluentMVCTesting.csproj.DotSettings ├── TestStack.FluentMVCTesting.nuspec ├── ViewResultTest.cs ├── packages.config └── readme.txt └── logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | bin 3 | _ReSharper* 4 | *.csproj.user 5 | *.ReSharper.user 6 | *.ReSharper 7 | *.user 8 | *.suo 9 | *.cache 10 | ~$* 11 | *~ 12 | *.log 13 | */NUnit*/tools 14 | */NhibernateProfiler*/tools 15 | packages 16 | /TestStack.FluentMVCTesting.Example/App_Data 17 | -------------------------------------------------------------------------------- /BREAKING_CHANGES.md: -------------------------------------------------------------------------------- 1 | # Version 3.0.0 2 | 3 | ## ShouldRedirectTo Method 4 | 5 | It used to be the case that when you invoked `ShouldRedirectTo` where `TController` is the same type as the `Controller` under test like this: 6 | 7 | var sut = new HomeController(); 8 | sut.WithCallTo(c => c.Index()) 9 | .ShouldRedirectTo(c => c.Index()); 10 | 11 | an `ActionResultAssertionException` would be thrown. 12 | 13 | An exception is no longer thrown. 14 | 15 | ### Reason 16 | 17 | There is no reason why a test like this one should fail. 18 | 19 | You can read the original problem specification and discussion [here](https://github.com/TestStack/TestStack.FluentMVCTesting/issues/47). 20 | 21 | 22 | ### Fix 23 | 24 | If your project has been impacted by this particular breaking change, you might consider reevaluate the correctness of the affected tests. 25 | 26 | ## Error Message Quotes 27 | 28 | Some error messages surrounded actual values in double quotes. Others surrounded the values in single quotes. In version 3.0.0 *all* values are surrounded in single quotes. 29 | 30 | ### Reason 31 | 32 | Consistency. 33 | 34 | ### Fix 35 | 36 | Amend any affected tests to expect single quotes instead of double quotes. 37 | 38 | ## Error Message Lambda Expression 39 | 40 | In error messages, lambda expressions arguments are now surrounded in a pair of parentheses. For example: 41 | 42 | ... to pass the given condition (model => (model.Property1 != null)) 43 | 44 | will now look like this: 45 | 46 | ... to pass the given condition ((model) => (model.Property1 != null)) 47 | 48 | As you can see, the argument called `model` is now surrounded in parentheses. 49 | 50 | ###Reason 51 | 52 | FluentMVCTesting now uses [ExpressionToString](https://github.com/JakeGinnivan/ExpressionToString) to humanize expression trees. ExpressionToString surrounds arguments in parentheses. 53 | 54 | ###Fix 55 | 56 | Amend any affected tests to expect lambda expression arguments to be surrounded in parentheses. 57 | 58 | # Version 2.0.0 59 | 60 | ## ShouldRenderFileStream Method 61 | 62 | The following overload of the `ShouldRenderFileStream` method has been *replaced*: 63 | 64 | public FileStreamResult ShouldRenderFileStream(string contentType = null) 65 | 66 | We place emphasis on the word "replace" because it is important to note that this overload has not been removed but replaced - you will not encounter a compile-time error if you upgrade, but you will encounter a logical error when you run your existing test. 67 | 68 | ### Reason 69 | 70 | The aforementioned overload has been replaced in order to enable an overload that takes a stream for comparison in a way that is consistent with the existing convention. 71 | 72 | ### Fix 73 | 74 | Use a [named argument](http://msdn.microsoft.com/en-gb/library/dd264739.aspx). 75 | 76 | As where you would have previously done this: 77 | 78 | ShouldRenderFileStream("application/json"); 79 | 80 | You must now do this: 81 | 82 | ShouldRenderFileStream(contentType: "application/json"); 83 | 84 | 85 | ## ShouldRenderFileMethod 86 | 87 | The `ShouldRenderFile` method has been removed. 88 | 89 | ### Reason 90 | 91 | The `ShouldRenderFile` method was ambiguous because it had the possibility to be interperted to test for a `FileResult` when in fact, it tested for a `FileContentResult`. 92 | 93 | It is for this reason that we introduced two unequivocal methods namely, `ShouldRenderAnyFile` and `ShouldRenderFileContents`. 94 | 95 | ### Fix 96 | 97 | Use the `ShouldRenderFileContents` method instead: 98 | 99 | ShouldRenderAnyFile() 100 | ShouldRenderAnyFile(contentType: "application/json") 101 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2013 Robert Moore and TestStack.FluentMVCTesting Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /NextVersion.txt: -------------------------------------------------------------------------------- 1 | 3.0.0 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TestStack.FluentMVCTesting 2 | ==================================== 3 | 4 | This library provides a fluent interface for creating terse and expressive tests against ASP.NET MVC controllers. This library is part of [TestStack](http://teststack.net/). 5 | 6 | This library is testing framework agnostic, so you can combine it with the testing library of your choice (e.g. NUnit, xUnit, etc.). 7 | 8 | The library is compatible with the AAA testing methodology, although it combines the Act and Assert parts together (but you can also have other assertions after the Fluent assertion). See the code examples below for more information. 9 | 10 | Documentation 11 | ------------- 12 | 13 | Please see [the documentation](http://fluentmvctesting.teststack.net/) for full installation and usage instructions. 14 | 15 | 16 | Installation 17 | ------------ 18 | 19 | You can install this library using NuGet into your Test Library; it will automatically reference System.Web and System.Web.Mvc (via NuGet packages, sorry it also installs a heap of other dependencies - it would be cool if Microsoft provided a package with just the MVC dll!) for you. 20 | 21 | If you are using ASP.NET MVC 5 (.NET 4.5+) then: 22 | 23 | Install-Package TestStack.FluentMVCTesting 24 | 25 | If you are using ASP.NET MVC 4 (.NET 4.0+) then: 26 | 27 | Install-Package TestStack.FluentMVCTesting.Mvc4 28 | 29 | If you are using ASP.NET MVC 3 (.NET 4.0+) then: 30 | 31 | Install-Package TestStack.FluentMVCTesting.Mvc3 32 | 33 | Known Issues 34 | ------------ 35 | 36 | If you get the following exception: 37 | 38 | System.Security.VerificationException : Method FluentMVCTesting.ControllerExtensions.WithCallTo: type argument 'MyApp.Controllers.MyController' violates the constraint of type parameter 'T'. 39 | 40 | It means you are referencing a version of System.Web.Mvc that isn't compatible with the one that was used to build the dll that was generated for the NuGet package. Ensure that you are using the correct package for your version of MVC and that you are using the [AspNetMvc packages on nuget.org](https://nuget.org/packages/aspnetmvc) rather than the dll from the GAC. 41 | 42 | Show me the code! 43 | ----------------- 44 | 45 | Make sure to check out [the documentation](http://fluentmvctesting.teststack.net/) for full usage instructions. 46 | 47 | Say you set up the following test class (this example with NUnit, but it will work for any test framework). 48 | 49 | ```c# 50 | using MyApp.Controllers; 51 | using NUnit.Framework; 52 | using TestStack.FluentMVCTesting; 53 | 54 | namespace MyApp.Tests.Controllers 55 | { 56 | [TestFixture] 57 | class HomeControllerShould 58 | { 59 | private HomeController _controller; 60 | 61 | [SetUp] 62 | public void Setup() 63 | { 64 | _controller = new HomeController(); 65 | } 66 | } 67 | } 68 | ``` 69 | 70 | Then you can create a test like this: 71 | 72 | ```c# 73 | [Test] 74 | public void Render_default_view_for_get_to_index() 75 | { 76 | _controller.WithCallTo(c => c.Index()).ShouldRenderDefaultView(); 77 | } 78 | ``` 79 | 80 | This checks that when `_controller.Index()` is called then the `ActionResult` that is returned is of type `ViewResult` and that the view name returned is either "Index" or "" (the default view for the Index action); easy huh? 81 | 82 | Here are some other random examples of assertions that you can make (see the documentation for the full list): 83 | 84 | ```c# 85 | var vm = new SomeViewModel(); 86 | _controller.WithModelErrors().WithCallTo(c => c.Index(vm)) 87 | .ShouldRenderDefaultView() 88 | .WithModel(vm); 89 | 90 | _controller.WithCallTo(c => c.Index()) 91 | .ShouldRenderDefaultView() 92 | .WithModel() 93 | .AndModelErrorFor(m => m.Property1).ThatEquals("The error message.") 94 | .AndModelErrorFor(m => m.Property2); 95 | 96 | _controller.WithCallTo(c => c.Index()) 97 | .ShouldRenderView("ViewName"); 98 | 99 | _controller.WithCallTo(c => c.Index()) 100 | .ShouldReturnEmptyResult(); 101 | 102 | _controller.WithCallTo(c => c.Index()) 103 | .ShouldRedirectTo("http://www.google.com.au/"); 104 | 105 | _controller.WithCallTo(c => c.ActionWithRedirectToAction()) 106 | .ShouldRedirectTo(c => c.ActionInSameController); 107 | 108 | _controller.WithCallTo(c => c.Index()) 109 | .ShouldRedirectTo(c => c.SomeAction()); 110 | 111 | _controller.WithCallTo(c => c.Index()) 112 | .ShouldRenderAnyFile("content/type"); 113 | 114 | _controller.WithCallTo(c => c.Index()) 115 | .ShouldRenderFileContents("text"); 116 | 117 | _controller.WithCallTo(c => c.Index()) 118 | .ShouldReturnContent("expected content"); 119 | 120 | _controller.WithCallTo(c => c.Index()) 121 | .ShouldGiveHttpStatus(404); 122 | 123 | _controller.WithCallTo(c => c.Index()).ShouldReturnJson(data => 124 | { 125 | Assert.That(data.SomeProperty, Is.EqualTo("SomeValue"); 126 | }); 127 | ``` 128 | 129 | Any questions, comments or additions? 130 | ------------------------------------- 131 | 132 | Leave an issue on the [issues page](https://github.com/TestStack/TestStack.FluentMVCTesting/issues) or send a [pull request](https://github.com/TestStack/TestStack.FluentMVCTesting/pulls). 133 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample.Tests/Controllers/ProductControllerTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NUnit.Framework; 3 | using TestStack.FluentMVCTesting.Sample.Controllers; 4 | 5 | namespace TestStack.FluentMVCTesting.Sample.Tests.Controllers 6 | { 7 | [TestFixture] 8 | class ProductControllerTests 9 | { 10 | private ProductController _controller; 11 | 12 | [SetUp] 13 | public void SetUp() 14 | { 15 | _controller = new ProductController(); 16 | } 17 | 18 | [Test] 19 | public void WhenViewingIndexPage_ThenShouldRedirectToProduct_WithId() 20 | { 21 | _controller.WithCallTo(c => c.Index()) 22 | .ShouldRedirectTo(c => c.Product()) 23 | .WithRouteValue("Id"); 24 | } 25 | 26 | [Test] 27 | public void WhenViewingIndexPage_ThenShouldRedirectToProduct_WithIdEqualToOne() 28 | { 29 | _controller.WithCallTo(c => c.Index()) 30 | .ShouldRedirectTo(c => c.Product()) 31 | .WithRouteValue("Id", 1); 32 | } 33 | 34 | [Test] 35 | public void UnknownUserAction_RedirectsToUser_WithEmptyGuidAndUnknownUserType() 36 | { 37 | _controller.WithCallTo(c => c.UnknownUser()) 38 | .ShouldRedirectTo(c => c.User()) 39 | .WithRouteValue("Id", Guid.Empty) 40 | .WithRouteValue("UserType", UserType.Unknown); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TestStack.FluentMVCTesting.Example.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TestStack.FluentMVCTesting.Example.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d9c8385f-0b68-48ec-9399-360df30e0707")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample.Tests/TestStack.FluentMVCTesting.Sample.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F36BC506-1076-49BF-A1A4-A76D6560AA64} 8 | Library 9 | Properties 10 | TestStack.FluentMVCTesting.Sample.Tests 11 | TestStack.FluentMVCTesting.Sample.Tests 12 | v4.5 13 | 512 14 | ..\ 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | 38 | ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 39 | True 40 | 41 | 42 | False 43 | ..\..\packages\NSubstitute.1.7.2.0\lib\NET45\NSubstitute.dll 44 | 45 | 46 | False 47 | ..\..\packages\NUnit.2.6.3\lib\nunit.framework.dll 48 | 49 | 50 | 51 | 52 | 53 | ..\..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.Helpers.dll 54 | True 55 | 56 | 57 | ..\..\packages\Microsoft.AspNet.Mvc.5.2.2\lib\net45\System.Web.Mvc.dll 58 | True 59 | 60 | 61 | ..\..\packages\Microsoft.AspNet.Razor.3.2.2\lib\net45\System.Web.Razor.dll 62 | True 63 | 64 | 65 | ..\..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.dll 66 | True 67 | 68 | 69 | ..\..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Deployment.dll 70 | True 71 | 72 | 73 | ..\..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Razor.dll 74 | True 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | {152ca00f-18d3-4cf5-8ca0-2c5b70cbea19} 92 | TestStack.FluentMVCTesting 93 | 94 | 95 | {fd292b9e-1493-428f-8af6-f7cf9cf463c5} 96 | TestStack.FluentMVCTesting.Sample 97 | 98 | 99 | 100 | 107 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample.Tests/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Optimization; 3 | 4 | namespace TestStack.FluentMVCTesting.Sample 5 | { 6 | public class BundleConfig 7 | { 8 | // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862 9 | public static void RegisterBundles(BundleCollection bundles) 10 | { 11 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 12 | "~/Scripts/jquery-{version}.js")); 13 | 14 | bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( 15 | "~/Scripts/jquery.validate*")); 16 | 17 | // Use the development version of Modernizr to develop with and learn from. Then, when you're 18 | // ready for production, use the build tool at http://modernizr.com to pick only the tests you need. 19 | bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( 20 | "~/Scripts/modernizr-*")); 21 | 22 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( 23 | "~/Scripts/bootstrap.js", 24 | "~/Scripts/respond.js")); 25 | 26 | bundles.Add(new StyleBundle("~/Content/css").Include( 27 | "~/Content/bootstrap.css", 28 | "~/Content/site.css")); 29 | 30 | // Set EnableOptimizations to false for debugging. For more information, 31 | // visit http://go.microsoft.com/fwlink/?LinkId=301862 32 | BundleTable.EnableOptimizations = true; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace TestStack.FluentMVCTesting.Sample 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/App_Start/IdentityConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.AspNet.Identity; 3 | using Microsoft.AspNet.Identity.EntityFramework; 4 | using Microsoft.AspNet.Identity.Owin; 5 | using Microsoft.Owin; 6 | using TestStack.FluentMVCTesting.Sample.Models; 7 | 8 | namespace TestStack.FluentMVCTesting.Sample 9 | { 10 | // Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application. 11 | 12 | public class ApplicationUserManager : UserManager 13 | { 14 | public ApplicationUserManager(IUserStore store) 15 | : base(store) 16 | { 17 | } 18 | 19 | public static ApplicationUserManager Create(IdentityFactoryOptions options, IOwinContext context) 20 | { 21 | var manager = new ApplicationUserManager(new UserStore(context.Get())); 22 | // Configure validation logic for usernames 23 | manager.UserValidator = new UserValidator(manager) 24 | { 25 | AllowOnlyAlphanumericUserNames = false, 26 | RequireUniqueEmail = true 27 | }; 28 | // Configure validation logic for passwords 29 | manager.PasswordValidator = new PasswordValidator 30 | { 31 | RequiredLength = 6, 32 | RequireNonLetterOrDigit = true, 33 | RequireDigit = true, 34 | RequireLowercase = true, 35 | RequireUppercase = true, 36 | }; 37 | // Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user 38 | // You can write your own provider and plug in here. 39 | manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider 40 | { 41 | MessageFormat = "Your security code is: {0}" 42 | }); 43 | manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider 44 | { 45 | Subject = "Security Code", 46 | BodyFormat = "Your security code is: {0}" 47 | }); 48 | manager.EmailService = new EmailService(); 49 | manager.SmsService = new SmsService(); 50 | var dataProtectionProvider = options.DataProtectionProvider; 51 | if (dataProtectionProvider != null) 52 | { 53 | manager.UserTokenProvider = new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity")); 54 | } 55 | return manager; 56 | } 57 | } 58 | 59 | public class EmailService : IIdentityMessageService 60 | { 61 | public Task SendAsync(IdentityMessage message) 62 | { 63 | // Plug in your email service here to send an email. 64 | return Task.FromResult(0); 65 | } 66 | } 67 | 68 | public class SmsService : IIdentityMessageService 69 | { 70 | public Task SendAsync(IdentityMessage message) 71 | { 72 | // Plug in your sms service here to send a text message. 73 | return Task.FromResult(0); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace TestStack.FluentMVCTesting.Sample 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/App_Start/Startup.Auth.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Identity; 2 | using Microsoft.AspNet.Identity.EntityFramework; 3 | using Microsoft.AspNet.Identity.Owin; 4 | using Microsoft.Owin; 5 | using Microsoft.Owin.Security.Cookies; 6 | using Microsoft.Owin.Security.DataProtection; 7 | using Microsoft.Owin.Security.Google; 8 | using Owin; 9 | using System; 10 | using TestStack.FluentMVCTesting.Sample.Models; 11 | 12 | namespace TestStack.FluentMVCTesting.Sample 13 | { 14 | public partial class Startup 15 | { 16 | // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864 17 | public void ConfigureAuth(IAppBuilder app) 18 | { 19 | // Configure the db context and user manager to use a single instance per request 20 | app.CreatePerOwinContext(ApplicationDbContext.Create); 21 | app.CreatePerOwinContext(ApplicationUserManager.Create); 22 | 23 | // Enable the application to use a cookie to store information for the signed in user 24 | // and to use a cookie to temporarily store information about a user logging in with a third party login provider 25 | // Configure the sign in cookie 26 | app.UseCookieAuthentication(new CookieAuthenticationOptions 27 | { 28 | AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 29 | LoginPath = new PathString("/Account/Login"), 30 | Provider = new CookieAuthenticationProvider 31 | { 32 | OnValidateIdentity = SecurityStampValidator.OnValidateIdentity( 33 | validateInterval: TimeSpan.FromMinutes(30), 34 | regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) 35 | } 36 | }); 37 | 38 | app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); 39 | 40 | // Uncomment the following lines to enable logging in with third party login providers 41 | //app.UseMicrosoftAccountAuthentication( 42 | // clientId: "", 43 | // clientSecret: ""); 44 | 45 | //app.UseTwitterAuthentication( 46 | // consumerKey: "", 47 | // consumerSecret: ""); 48 | 49 | //app.UseFacebookAuthentication( 50 | // appId: "", 51 | // appSecret: ""); 52 | 53 | //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions() 54 | //{ 55 | // ClientId = "", 56 | // ClientSecret = "" 57 | //}); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Content/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Set padding to keep content from hitting the edges */ 7 | .body-content { 8 | padding-left: 15px; 9 | padding-right: 15px; 10 | } 11 | 12 | /* Set width on the form input elements since they're 100% wide by default */ 13 | input, 14 | select, 15 | textarea { 16 | max-width: 280px; 17 | } 18 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | 7 | namespace TestStack.FluentMVCTesting.Sample.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | public ActionResult Index() 12 | { 13 | return View(); 14 | } 15 | 16 | public ActionResult About() 17 | { 18 | ViewBag.Message = "Your application description page."; 19 | 20 | return View(); 21 | } 22 | 23 | public ActionResult Contact() 24 | { 25 | ViewBag.Message = "Your contact page."; 26 | 27 | return View(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Controllers/ProductController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | 4 | namespace TestStack.FluentMVCTesting.Sample.Controllers 5 | { 6 | public enum UserType 7 | { 8 | Unknown = 0 9 | } 10 | 11 | public class ProductController : Controller 12 | { 13 | public ActionResult Product() 14 | { 15 | return View(); 16 | } 17 | 18 | public ActionResult Index() 19 | { 20 | return RedirectToAction("Product", new { Id = 1 }); 21 | } 22 | 23 | public ActionResult User() 24 | { 25 | return View(); 26 | } 27 | 28 | public ActionResult UnknownUser() 29 | { 30 | return RedirectToAction("User", new { Id = Guid.Empty, UserType = UserType.Unknown }); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="TestStack.FluentMVCTesting.Sample.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Optimization; 7 | using System.Web.Routing; 8 | 9 | namespace TestStack.FluentMVCTesting.Sample 10 | { 11 | public class MvcApplication : System.Web.HttpApplication 12 | { 13 | protected void Application_Start() 14 | { 15 | AreaRegistration.RegisterAllAreas(); 16 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 17 | RouteConfig.RegisterRoutes(RouteTable.Routes); 18 | BundleConfig.RegisterBundles(BundleTable.Bundles); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Models/AccountViewModels.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace TestStack.FluentMVCTesting.Sample.Models 4 | { 5 | public class ExternalLoginConfirmationViewModel 6 | { 7 | [Required] 8 | [EmailAddress] 9 | [Display(Name = "Email")] 10 | public string Email { get; set; } 11 | } 12 | 13 | public class ExternalLoginListViewModel 14 | { 15 | public string Action { get; set; } 16 | public string ReturnUrl { get; set; } 17 | } 18 | 19 | public class ManageUserViewModel 20 | { 21 | [Required] 22 | [DataType(DataType.Password)] 23 | [Display(Name = "Current password")] 24 | public string OldPassword { get; set; } 25 | 26 | [Required] 27 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 28 | [DataType(DataType.Password)] 29 | [Display(Name = "New password")] 30 | public string NewPassword { get; set; } 31 | 32 | [DataType(DataType.Password)] 33 | [Display(Name = "Confirm new password")] 34 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 35 | public string ConfirmPassword { get; set; } 36 | } 37 | 38 | public class LoginViewModel 39 | { 40 | [Required] 41 | [EmailAddress] 42 | [Display(Name = "Email")] 43 | public string Email { get; set; } 44 | 45 | [Required] 46 | [DataType(DataType.Password)] 47 | [Display(Name = "Password")] 48 | public string Password { get; set; } 49 | 50 | [Display(Name = "Remember me?")] 51 | public bool RememberMe { get; set; } 52 | } 53 | 54 | public class RegisterViewModel 55 | { 56 | [Required] 57 | [EmailAddress] 58 | [Display(Name = "Email")] 59 | public string Email { get; set; } 60 | 61 | [Required] 62 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 63 | [DataType(DataType.Password)] 64 | [Display(Name = "Password")] 65 | public string Password { get; set; } 66 | 67 | [DataType(DataType.Password)] 68 | [Display(Name = "Confirm password")] 69 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 70 | public string ConfirmPassword { get; set; } 71 | } 72 | 73 | public class ResetPasswordViewModel 74 | { 75 | [Required] 76 | [EmailAddress] 77 | [Display(Name = "Email")] 78 | public string Email { get; set; } 79 | 80 | [Required] 81 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 82 | [DataType(DataType.Password)] 83 | [Display(Name = "Password")] 84 | public string Password { get; set; } 85 | 86 | [DataType(DataType.Password)] 87 | [Display(Name = "Confirm password")] 88 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 89 | public string ConfirmPassword { get; set; } 90 | 91 | public string Code { get; set; } 92 | } 93 | 94 | public class ForgotPasswordViewModel 95 | { 96 | [Required] 97 | [EmailAddress] 98 | [Display(Name = "Email")] 99 | public string Email { get; set; } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Models/IdentityModels.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNet.Identity; 4 | using Microsoft.AspNet.Identity.EntityFramework; 5 | 6 | namespace TestStack.FluentMVCTesting.Sample.Models 7 | { 8 | // You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more. 9 | public class ApplicationUser : IdentityUser 10 | { 11 | public async Task GenerateUserIdentityAsync(UserManager manager) 12 | { 13 | // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType 14 | var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); 15 | // Add custom user claims here 16 | return userIdentity; 17 | } 18 | } 19 | 20 | public class ApplicationDbContext : IdentityDbContext 21 | { 22 | public ApplicationDbContext() 23 | : base("DefaultConnection", throwIfV1Schema: false) 24 | { 25 | } 26 | 27 | public static ApplicationDbContext Create() 28 | { 29 | return new ApplicationDbContext(); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Project_Readme.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Your ASP.NET application 6 | 95 | 96 | 97 | 98 | 102 | 103 |
104 |
105 |

This application consists of:

106 |
    107 |
  • Sample pages showing basic nav between Home, About, and Contact
  • 108 |
  • Theming using Bootstrap
  • 109 |
  • Authentication, if selected, shows how to register and sign in
  • 110 |
  • ASP.NET features managed using NuGet
  • 111 |
112 |
113 | 114 | 131 | 132 |
133 |

Deploy

134 | 139 |
140 | 141 |
142 |

Get help

143 | 147 |
148 |
149 | 150 | 151 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TestStack.FluentMVCTesting.Sample")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TestStack.FluentMVCTesting.Sample")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("33ce0a3c-b39a-412a-8792-c99eae5aa4a9")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Scripts/_references.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TestStack/TestStack.FluentMVCTesting/7e81853353fe858f214ffb4a990bad0784e4ae81/Samples/TestStack.FluentMVCTesting.Sample/Scripts/_references.js -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Scripts/jquery.validate.unobtrusive.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /* 16 | ** Unobtrusive validation support library for jQuery and jQuery Validate 17 | ** Copyright (C) Microsoft Corporation. All rights reserved. 18 | */ 19 | (function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("
  • ").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this);b.data("validator").resetForm();b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(c){var b=a(c),d=b.data(e),f=a.proxy(n,c);if(!d){d={options:{errorClass:"input-validation-error",errorElement:"span",errorPlacement:a.proxy(m,c),invalidHandler:a.proxy(l,c),messages:{},rules:{},success:a.proxy(k,c)},attachValidation:function(){b.unbind("reset."+e,f).bind("reset."+e,f).validate(this.options)},validate:function(){b.validate();return b.valid()}};b.data(e,d)}return d}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(b){var c=a(b).parents("form").andSelf().add(a(b).find("form")).filter("form");a(b).find(":input").filter("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});c.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){return a(b.form).find(":input").filter("[name='"+f(c)+"']").val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery); -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Scripts/respond.min.js: -------------------------------------------------------------------------------- 1 | /* NUGET: BEGIN LICENSE TEXT 2 | * 3 | * Microsoft grants you the right to use these script files for the sole 4 | * purpose of either: (i) interacting through your browser with the Microsoft 5 | * website or online service, subject to the applicable licensing or use 6 | * terms; or (ii) using the files as included with a Microsoft product subject 7 | * to that product's license terms. Microsoft reserves all other rights to the 8 | * files not expressly granted by Microsoft, whether by implication, estoppel 9 | * or otherwise. Insofar as a script file is dual licensed under GPL, 10 | * Microsoft neither took the code under GPL nor distributes it thereunder but 11 | * under the terms set out in this paragraph. All notices and licenses 12 | * below are for informational purposes only. 13 | * 14 | * NUGET: END LICENSE TEXT */ 15 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ 16 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ 17 | window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='­';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document); 18 | 19 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */ 20 | (function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this); -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Owin; 2 | using Owin; 3 | 4 | [assembly: OwinStartupAttribute(typeof(TestStack.FluentMVCTesting.Sample.Startup))] 5 | namespace TestStack.FluentMVCTesting.Sample 6 | { 7 | public partial class Startup 8 | { 9 | public void Configuration(IAppBuilder app) 10 | { 11 | ConfigureAuth(app); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/ConfirmEmail.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "ConfirmAccount"; 3 | } 4 | 5 |

    @ViewBag.Title.

    6 |
    7 |

    8 | Thank you for confirming your account. Please @Html.ActionLink("click here to log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" }) 9 |

    10 |
    11 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/ExternalLoginConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @model TestStack.FluentMVCTesting.Sample.Models.ExternalLoginConfirmationViewModel 2 | @{ 3 | ViewBag.Title = "Register"; 4 | } 5 |

    @ViewBag.Title.

    6 |

    Associate your @ViewBag.LoginProvider account.

    7 | 8 | @using (Html.BeginForm("ExternalLoginConfirmation", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 | 12 |

    Association Form

    13 |
    14 | @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 15 |

    16 | You've successfully authenticated with @ViewBag.LoginProvider. 17 | Please enter a user name for this site below and click the Register button to finish 18 | logging in. 19 |

    20 |
    21 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 22 |
    23 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 24 | @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" }) 25 |
    26 |
    27 |
    28 |
    29 | 30 |
    31 |
    32 | } 33 | 34 | @section Scripts { 35 | @Scripts.Render("~/bundles/jqueryval") 36 | } 37 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/ExternalLoginFailure.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Login Failure"; 3 | } 4 | 5 |

    @ViewBag.Title.

    6 |

    Unsuccessful login with service.

    7 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/ForgotPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model TestStack.FluentMVCTesting.Sample.Models.ForgotPasswordViewModel 2 | @{ 3 | ViewBag.Title = "Forgot your password?"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("ForgotPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Enter your email.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
    15 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 |
    22 | 23 |
    24 |
    25 | } 26 | 27 | @section Scripts { 28 | @Scripts.Render("~/bundles/jqueryval") 29 | } 30 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/ForgotPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Forgot Password Confirmation"; 3 | } 4 | 5 |
    6 |

    @ViewBag.Title.

    7 |
    8 |
    9 |

    10 | Please check your email to reset your password. 11 |

    12 |
    13 | 14 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @using TestStack.FluentMVCTesting.Sample.Models 2 | @model LoginViewModel 3 | 4 | @{ 5 | ViewBag.Title = "Log in"; 6 | } 7 | 8 |

    @ViewBag.Title.

    9 |
    10 |
    11 |
    12 | @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 13 | { 14 | @Html.AntiForgeryToken() 15 |

    Use a local account to log in.

    16 |
    17 | @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 18 |
    19 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 20 |
    21 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 22 | @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" }) 23 |
    24 |
    25 |
    26 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 27 |
    28 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 29 | @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" }) 30 |
    31 |
    32 |
    33 |
    34 |
    35 | @Html.CheckBoxFor(m => m.RememberMe) 36 | @Html.LabelFor(m => m.RememberMe) 37 |
    38 |
    39 |
    40 |
    41 |
    42 | 43 |
    44 |
    45 |

    46 | @Html.ActionLink("Register as a new user", "Register") 47 |

    48 | @* Enable this once you have account confirmation enabled for password reset functionality 49 |

    50 | @Html.ActionLink("Forgot your password?", "ForgotPassword") 51 |

    *@ 52 | } 53 |
    54 |
    55 |
    56 |
    57 | @Html.Partial("_ExternalLoginsListPartial", new ExternalLoginListViewModel { Action = "ExternalLogin", ReturnUrl = ViewBag.ReturnUrl }) 58 |
    59 |
    60 |
    61 | @section Scripts { 62 | @Scripts.Render("~/bundles/jqueryval") 63 | } -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/Manage.cshtml: -------------------------------------------------------------------------------- 1 | @using TestStack.FluentMVCTesting.Sample.Models; 2 | @using Microsoft.AspNet.Identity; 3 | @{ 4 | ViewBag.Title = "Manage Account"; 5 | } 6 | 7 |

    @ViewBag.Title.

    8 | 9 |

    @ViewBag.StatusMessage

    10 |
    11 |
    12 | @if (ViewBag.HasLocalPassword) 13 | { 14 | @Html.Partial("_ChangePasswordPartial") 15 | } 16 | else 17 | { 18 | @Html.Partial("_SetPasswordPartial") 19 | } 20 | 21 |
    22 | @Html.Action("RemoveAccountList") 23 | @Html.Partial("_ExternalLoginsListPartial", new ExternalLoginListViewModel { Action = "LinkLogin", ReturnUrl = ViewBag.ReturnUrl }) 24 |
    25 |
    26 |
    27 | @section Scripts { 28 | @Scripts.Render("~/bundles/jqueryval") 29 | } 30 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @model TestStack.FluentMVCTesting.Sample.Models.RegisterViewModel 2 | @{ 3 | ViewBag.Title = "Register"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Create a new account.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 |
    15 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 16 |
    17 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 18 |
    19 |
    20 |
    21 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 22 |
    23 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 24 |
    25 |
    26 |
    27 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 28 |
    29 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 30 |
    31 |
    32 |
    33 |
    34 | 35 |
    36 |
    37 | } 38 | 39 | @section Scripts { 40 | @Scripts.Render("~/bundles/jqueryval") 41 | } 42 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/ResetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model TestStack.FluentMVCTesting.Sample.Models.ResetPasswordViewModel 2 | @{ 3 | ViewBag.Title = "Reset password"; 4 | } 5 | 6 |

    @ViewBag.Title.

    7 | 8 | @using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 |

    Reset your password.

    12 |
    13 | @Html.ValidationSummary("", new { @class = "text-danger" }) 14 | @Html.HiddenFor(model => model.Code) 15 |
    16 | @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" }) 17 |
    18 | @Html.TextBoxFor(m => m.Email, new { @class = "form-control" }) 19 |
    20 |
    21 |
    22 | @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) 23 |
    24 | @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) 25 |
    26 |
    27 |
    28 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 29 |
    30 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 31 |
    32 |
    33 |
    34 |
    35 | 36 |
    37 |
    38 | } 39 | 40 | @section Scripts { 41 | @Scripts.Render("~/bundles/jqueryval") 42 | } 43 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/ResetPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Reset password confirmation"; 3 | } 4 | 5 |
    6 |

    @ViewBag.Title.

    7 |
    8 |
    9 |

    10 | Your password has been reset. Please @Html.ActionLink("click here to log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" }) 11 |

    12 |
    13 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/_ChangePasswordPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNet.Identity 2 | @model TestStack.FluentMVCTesting.Sample.Models.ManageUserViewModel 3 | 4 |

    You're logged in as @User.Identity.GetUserName().

    5 | 6 | @using (Html.BeginForm("Manage", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 7 | { 8 | @Html.AntiForgeryToken() 9 |

    Change Password Form

    10 |
    11 | @Html.ValidationSummary("", new { @class = "text-danger" }) 12 |
    13 | @Html.LabelFor(m => m.OldPassword, new { @class = "col-md-2 control-label" }) 14 |
    15 | @Html.PasswordFor(m => m.OldPassword, new { @class = "form-control" }) 16 |
    17 |
    18 |
    19 | @Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" }) 20 |
    21 | @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" }) 22 |
    23 |
    24 |
    25 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 26 |
    27 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 28 |
    29 |
    30 | 31 |
    32 |
    33 | 34 |
    35 |
    36 | } 37 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/_ExternalLoginsListPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using TestStack.FluentMVCTesting.Sample.Models 2 | @model ExternalLoginListViewModel 3 | @using Microsoft.Owin.Security 4 | 5 |

    Use another service to log in.

    6 |
    7 | @{ 8 | var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes(); 9 | if (loginProviders.Count() == 0) 10 | { 11 |
    12 |

    There are no external authentication services configured. See this article 13 | for details on setting up this ASP.NET application to support logging in via external services.

    14 |
    15 | } 16 | else 17 | { 18 | using (Html.BeginForm(Model.Action, "Account", new { ReturnUrl = Model.ReturnUrl })) 19 | { 20 | @Html.AntiForgeryToken() 21 |
    22 |

    23 | @foreach (AuthenticationDescription p in loginProviders) 24 | { 25 | 26 | } 27 |

    28 |
    29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/_RemoveAccountPartial.cshtml: -------------------------------------------------------------------------------- 1 | @model ICollection 2 | 3 | @if (Model.Count > 0) 4 | { 5 |

    Registered Logins

    6 | 7 | 8 | @foreach (var account in Model) 9 | { 10 | 11 | 12 | 30 | 31 | } 32 | 33 |
    @account.LoginProvider 13 | @if (ViewBag.ShowRemoveButton) 14 | { 15 | using (Html.BeginForm("Disassociate", "Account")) 16 | { 17 | @Html.AntiForgeryToken() 18 |
    19 | @Html.Hidden("loginProvider", account.LoginProvider) 20 | @Html.Hidden("providerKey", account.ProviderKey) 21 | 22 |
    23 | } 24 | } 25 | else 26 | { 27 | @:   28 | } 29 |
    34 | } 35 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Account/_SetPasswordPartial.cshtml: -------------------------------------------------------------------------------- 1 | @model TestStack.FluentMVCTesting.Sample.Models.ManageUserViewModel 2 | 3 |

    4 | You do not have a local username/password for this site. Add a local 5 | account so you can log in without an external login. 6 |

    7 | 8 | @using (Html.BeginForm("Manage", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" })) 9 | { 10 | @Html.AntiForgeryToken() 11 | 12 |

    Create Local Login

    13 |
    14 | @Html.ValidationSummary("", new { @class = "text-danger" }) 15 |
    16 | @Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" }) 17 |
    18 | @Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" }) 19 |
    20 |
    21 |
    22 | @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" }) 23 |
    24 | @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" }) 25 |
    26 |
    27 |
    28 |
    29 | 30 |
    31 |
    32 | } 33 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "About"; 3 | } 4 |

    @ViewBag.Title.

    5 |

    @ViewBag.Message

    6 | 7 |

    Use this area to provide additional information.

    8 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Home/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Contact"; 3 | } 4 |

    @ViewBag.Title.

    5 |

    @ViewBag.Message

    6 | 7 |
    8 | One Microsoft Way
    9 | Redmond, WA 98052-6399
    10 | P: 11 | 425.555.0100 12 |
    13 | 14 |
    15 | Support: Support@example.com
    16 | Marketing: Marketing@example.com 17 |
    -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Home Page"; 3 | } 4 | 5 |
    6 |

    ASP.NET

    7 |

    ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.

    8 |

    Learn more »

    9 |
    10 | 11 |
    12 |
    13 |

    Getting started

    14 |

    15 | ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that 16 | enables a clean separation of concerns and gives you full control over markup 17 | for enjoyable, agile development. 18 |

    19 |

    Learn more »

    20 |
    21 |
    22 |

    Get more libraries

    23 |

    NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.

    24 |

    Learn more »

    25 |
    26 |
    27 |

    Web Hosting

    28 |

    You can easily find a web hosting company that offers the right mix of features and price for your applications.

    29 |

    Learn more »

    30 |
    31 |
    -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Product/Product.cshtml: -------------------------------------------------------------------------------- 1 | @model dynamic 2 | 3 | @{ 4 | ViewBag.Title = "title"; 5 | Layout = "_Layout"; 6 | } 7 | 8 |

    title

    9 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model System.Web.Mvc.HandleErrorInfo 2 | 3 | @{ 4 | ViewBag.Title = "Error"; 5 | } 6 | 7 |

    Error.

    8 |

    An error occurred while processing your request.

    9 | 10 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewBag.Title - My ASP.NET Application 7 | @Styles.Render("~/Content/css") 8 | @Scripts.Render("~/bundles/modernizr") 9 | 10 | 11 | 12 | 32 |
    33 | @RenderBody() 34 |
    35 |
    36 |

    © @DateTime.Now.Year - My ASP.NET Application

    37 |
    38 |
    39 | 40 | @Scripts.Render("~/bundles/jquery") 41 | @Scripts.Render("~/bundles/bootstrap") 42 | @RenderSection("scripts", required: false) 43 | 44 | 45 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNet.Identity 2 | @if (Request.IsAuthenticated) 3 | { 4 | using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" })) 5 | { 6 | @Html.AntiForgeryToken() 7 | 8 | 14 | } 15 | } 16 | else 17 | { 18 | 22 | } 23 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
    7 |
    8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 |
    10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TestStack/TestStack.FluentMVCTesting/7e81853353fe858f214ffb4a990bad0784e4ae81/Samples/TestStack.FluentMVCTesting.Sample/favicon.ico -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TestStack/TestStack.FluentMVCTesting/7e81853353fe858f214ffb4a990bad0784e4ae81/Samples/TestStack.FluentMVCTesting.Sample/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TestStack/TestStack.FluentMVCTesting/7e81853353fe858f214ffb4a990bad0784e4ae81/Samples/TestStack.FluentMVCTesting.Sample/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TestStack/TestStack.FluentMVCTesting/7e81853353fe858f214ffb4a990bad0784e4ae81/Samples/TestStack.FluentMVCTesting.Sample/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Samples/TestStack.FluentMVCTesting.Sample/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc3.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TestStack.FluentMVCTesting.Mvc3.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TestStack.FluentMVCTesting.Mvc3.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d4c7a8b3-c908-477a-8e3a-3dcf73f069ee")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc3.Tests/TestStack.FluentMVCTesting.Mvc3.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F6A48378-7254-4B72-A02B-5E1023533A1B} 8 | Library 9 | Properties 10 | TestStack.FluentMVCTesting.Mvc3.Tests 11 | TestStack.FluentMVCTesting.Mvc3.Tests 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 36 | True 37 | 38 | 39 | False 40 | ..\packages\NSubstitute.1.7.2.0\lib\NET40\NSubstitute.dll 41 | 42 | 43 | False 44 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll 45 | 46 | 47 | 48 | 49 | 50 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.Helpers.dll 51 | True 52 | 53 | 54 | ..\packages\Microsoft.AspNet.Mvc.3.0.20105.1\lib\net40\System.Web.Mvc.dll 55 | True 56 | 57 | 58 | ..\packages\Microsoft.AspNet.Razor.1.0.20105.408\lib\net40\System.Web.Razor.dll 59 | True 60 | 61 | 62 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.dll 63 | True 64 | 65 | 66 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.Deployment.dll 67 | True 68 | 69 | 70 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.Razor.dll 71 | True 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | {17e643b6-0448-4e6f-a8d8-d726154d73e1} 85 | TestStack.FluentMVCTesting.Mvc3 86 | 87 | 88 | 89 | 90 | Designer 91 | 92 | 93 | 94 | 101 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc3.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc3/TestStack.FluentMVCTesting.Mvc3.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {17E643B6-0448-4E6F-A8D8-D726154D73E1} 9 | Library 10 | Properties 11 | TestStack.FluentMVCTesting 12 | TestStack.FluentMVCTesting.Mvc3 13 | v4.0 14 | 512 15 | ..\ 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | false 36 | 37 | 38 | 39 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 40 | True 41 | 42 | 43 | 44 | 45 | 46 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.Helpers.dll 47 | True 48 | 49 | 50 | ..\packages\Microsoft.AspNet.Mvc.3.0.20105.1\lib\net40\System.Web.Mvc.dll 51 | True 52 | 53 | 54 | ..\packages\Microsoft.AspNet.Razor.1.0.20105.408\lib\net40\System.Web.Razor.dll 55 | True 56 | 57 | 58 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.dll 59 | True 60 | 61 | 62 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.Deployment.dll 63 | True 64 | 65 | 66 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.Razor.dll 67 | True 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc3/TestStack.FluentMVCTesting.Mvc3.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | TestStack.FluentMVCTesting.Mvc3 6 | 7 | 8 | 1.0.0 9 | 10 | 11 | Robert Moore, TestStack 12 | 13 | 14 | Simple, terse, fluent unit testing of ASP.NET MVC Controllers. 15 | ASP.NET MVC 3 version; install FluentMVCTesting if you are using MVC5 or FluentMVCTesting.Mvc4 if you are using MVC4. 16 | 17 | 18 | https://github.com/TestStack/TestStack.FluentMVCTesting 19 | 20 | 21 | https://github.com/TestStack/TestStack.FluentMVCTesting/blob/master/LICENSE.txt 22 | 23 | 24 | https://raw.github.com/TestStack/TestStack.FluentMVCTesting/master/logo.png 25 | 26 | 27 | fluent, mvc, asp.net, testing, terse 28 | 29 | 30 | en-US 31 | 32 | 33 | 34 | 35 | 36 | For breaking changes from previous versions see 37 | https://github.com/TestStack/TestStack.FluentMVCTesting/blob/master/BREAKING_CHANGES.md 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc3/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc4.Tests/TestStack.FluentMVCTesting.Mvc4.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5264EC40-E039-4634-B92D-79AD3656A23E} 8 | Library 9 | Properties 10 | TestStack.FluentMVCTesting.Mvc4.Tests 11 | TestStack.FluentMVCTesting.Mvc4.Tests 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 36 | True 37 | 38 | 39 | False 40 | ..\packages\NSubstitute.1.7.2.0\lib\NET40\NSubstitute.dll 41 | 42 | 43 | False 44 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll 45 | 46 | 47 | 48 | 49 | 50 | ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll 51 | True 52 | 53 | 54 | ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll 55 | True 56 | 57 | 58 | ..\packages\Microsoft.AspNet.Razor.2.0.20710.0\lib\net40\System.Web.Razor.dll 59 | True 60 | 61 | 62 | ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll 63 | True 64 | 65 | 66 | ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll 67 | True 68 | 69 | 70 | ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll 71 | True 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | {bf71218d-3e60-4146-bdf5-da15ef29f0aa} 82 | TestStack.FluentMVCTesting.Mvc4 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc4.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc4/TestStack.FluentMVCTesting.Mvc4.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {BF71218D-3E60-4146-BDF5-DA15EF29F0AA} 8 | Library 9 | Properties 10 | TestStack.FluentMVCTesting.Mvc4 11 | TestStack.FluentMVCTesting.Mvc4 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 36 | True 37 | 38 | 39 | 40 | 41 | 42 | ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.Helpers.dll 43 | True 44 | 45 | 46 | ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll 47 | True 48 | 49 | 50 | ..\packages\Microsoft.AspNet.Razor.2.0.20710.0\lib\net40\System.Web.Razor.dll 51 | True 52 | 53 | 54 | ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.dll 55 | True 56 | 57 | 58 | ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Deployment.dll 59 | True 60 | 61 | 62 | ..\packages\Microsoft.AspNet.WebPages.2.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll 63 | True 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Designer 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc4/TestStack.FluentMVCTesting.Mvc4.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | TestStack.FluentMVCTesting.Mvc4 6 | 7 | 8 | 1.0.0 9 | 10 | 11 | Robert Moore, TestStack 12 | 13 | 14 | Simple, terse, fluent unit testing of ASP.NET MVC Controllers. 15 | ASP.NET MVC 4 version; install FluentMVCTesting if you are using MVC5 or FluentMVCTesting.Mvc3 if you are using MVC3. 16 | 17 | 18 | https://github.com/TestStack/TestStack.FluentMVCTesting 19 | 20 | 21 | https://github.com/TestStack/TestStack.FluentMVCTesting/blob/master/LICENSE.txt 22 | 23 | 24 | https://raw.github.com/TestStack/TestStack.FluentMVCTesting/master/logo.png 25 | 26 | 27 | fluent, mvc, asp.net, testing, terse 28 | 29 | 30 | en-US 31 | 32 | 33 | 34 | 35 | 36 | For breaking changes from previous versions see 37 | https://github.com/TestStack/TestStack.FluentMVCTesting/blob/master/BREAKING_CHANGES.md 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Mvc4/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/AsyncControllerTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using TestStack.FluentMVCTesting.Tests.TestControllers; 3 | 4 | namespace TestStack.FluentMVCTesting.Tests 5 | { 6 | class AsyncControllersShould 7 | { 8 | private AsyncController _controller; 9 | 10 | [SetUp] 11 | public void Setup() 12 | { 13 | _controller = new AsyncController(); 14 | } 15 | 16 | [Test] 17 | public void Work_correctly_for_valid_check() 18 | { 19 | _controller.WithCallTo(c => c.AsyncViewAction()) 20 | .ShouldRenderDefaultView(); 21 | } 22 | 23 | [Test] 24 | public void Work_correctly_for_invalid_check() 25 | { 26 | Assert.Throws( 27 | () => _controller.WithCallTo(c => c.AsyncViewAction()).ShouldGiveHttpStatus() 28 | ); 29 | } 30 | [Test] 31 | public void Work_correctly_for_valid_child_action_check() 32 | { 33 | _controller.WithCallToChild(c => c.AsyncChildViewAction()) 34 | .ShouldRenderDefaultView(); 35 | } 36 | 37 | [Test] 38 | public void Work_correctly_for_invalid_child_action_check() 39 | { 40 | Assert.Throws( 41 | () => _controller.WithCallToChild(c => c.AsyncViewAction()) 42 | ); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/ControllerResultTestTests/ControllerResultTestTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | using System.Web.Mvc; 7 | using TestStack.FluentMVCTesting.Tests.TestControllers; 8 | 9 | namespace TestStack.FluentMVCTesting.Tests 10 | { 11 | [TestFixture] 12 | partial class ControllerResultTestShould 13 | { 14 | private ControllerResultTestController _controller; 15 | 16 | [SetUp] 17 | public void Setup() 18 | { 19 | _controller = new ControllerResultTestController(); 20 | } 21 | 22 | #region General Tests 23 | // Expected action return types for the different types of assertions 24 | private static readonly List> ReturnTypes = new List> 25 | { 26 | ReturnType(t => t.ShouldReturnEmptyResult()), 27 | ReturnType(t => t.ShouldRedirectTo("")), 28 | ReturnType(t => t.ShouldRedirectTo(c => c.EmptyResult)), 29 | ReturnType(t => t.ShouldRedirectTo(c => c.SomeAction())), 30 | ReturnType(t => t.ShouldRenderView("")), 31 | ReturnType(t => t.ShouldRenderDefaultView()), 32 | ReturnType(t => t.ShouldRenderPartialView("")), 33 | ReturnType(t => t.ShouldRenderDefaultPartialView()), 34 | ReturnType(t => t.ShouldRenderFileContents()), 35 | ReturnType(t => t.ShouldRenderFileContents(new byte[0])), 36 | ReturnType(t => t.ShouldRenderFileContents(new byte[0], "")), 37 | ReturnType(t => t.ShouldRenderFileContents("")), 38 | ReturnType(t => t.ShouldRenderFileContents("", "")), 39 | ReturnType(t => t.ShouldRenderFileContents("", "", Encoding.UTF8)), 40 | ReturnType(t => t.ShouldRenderFilePath()), 41 | ReturnType(t => t.ShouldRenderFilePath("")), 42 | ReturnType(t => t.ShouldRenderFilePath("", "")), 43 | ReturnType(t => t.ShouldRenderFileStream()), 44 | ReturnType(t => t.ShouldRenderFileStream(new MemoryStream())), 45 | ReturnType(t => t.ShouldRenderFileStream(contentType: "")), 46 | ReturnType(t => t.ShouldRenderFileStream(new MemoryStream(), "")), 47 | ReturnType(t => t.ShouldRenderFileStream(new byte[0])), 48 | ReturnType(t => t.ShouldRenderFileStream(new byte[0], "")), 49 | ReturnType(t => t.ShouldRenderFileStream("")), 50 | ReturnType(t => t.ShouldRenderFileStream("", "")), 51 | ReturnType(t => t.ShouldRenderFileStream("", "", Encoding.UTF8)), 52 | ReturnType(t => t.ShouldRenderAnyFile()), 53 | ReturnType(t => t.ShouldGiveHttpStatus()), 54 | ReturnType(t => t.ShouldReturnJson()), 55 | ReturnType(t => t.ShouldReturnContent()), 56 | ReturnType(t => t.ShouldReturnContent("")), 57 | ReturnType(t => t.ShouldReturnContent("", "")), 58 | ReturnType(t => t.ShouldReturnContent("", "", Encoding.UTF8)) 59 | }; 60 | 61 | [Test] 62 | [TestCaseSource("ReturnTypes")] 63 | public void Check_return_type(Tuple test) 64 | { 65 | var exception = Assert.Throws(() => 66 | test.Item2(_controller.WithCallTo(c => c.RandomResult())) 67 | ); 68 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected action result to be a {0}, but instead received a RandomResult.", test.Item1))); 69 | } 70 | 71 | [Test] 72 | [TestCaseSource("ReturnTypes")] 73 | public void Check_null_return(Tuple test) 74 | { 75 | var exception = Assert.Throws(() => 76 | test.Item2(_controller.WithCallTo(c => c.Null())) 77 | ); 78 | Assert.That(exception.Message, Is.EqualTo(string.Format("Received null action result when expecting {0}.", test.Item1))); 79 | } 80 | #endregion 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/ControllerResultTestTests/ShouldGiveHttpStatusTests.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using NUnit.Framework; 3 | using TestStack.FluentMVCTesting.Tests.TestControllers; 4 | 5 | namespace TestStack.FluentMVCTesting.Tests 6 | { 7 | partial class ControllerResultTestShould 8 | { 9 | [Test] 10 | public void Check_for_http_not_found() 11 | { 12 | _controller.WithCallTo(c => c.NotFound()).ShouldGiveHttpStatus(HttpStatusCode.NotFound); 13 | } 14 | 15 | [Test] 16 | public void Check_for_http_status() 17 | { 18 | _controller.WithCallTo(c => c.StatusCode()).ShouldGiveHttpStatus(ControllerResultTestController.Code); 19 | } 20 | 21 | [Test] 22 | public void Check_for_invalid_http_status() 23 | { 24 | var exception = Assert.Throws(() => 25 | _controller.WithCallTo(c => c.StatusCode()).ShouldGiveHttpStatus(ControllerResultTestController.Code + 1) 26 | ); 27 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected HTTP status code to be '{0}', but instead received a '{1}'.", ControllerResultTestController.Code + 1, ControllerResultTestController.Code))); 28 | } 29 | 30 | [Test] 31 | public void Return_the_http_status_result() 32 | { 33 | var expected = _controller.StatusCode(); 34 | var actual = _controller.WithCallTo(c => c.StatusCode()) 35 | .ShouldGiveHttpStatus(); 36 | Assert.That(actual.StatusCode,Is.EqualTo(expected.StatusCode)); 37 | Assert.That(actual.StatusDescription, Is.EqualTo(expected.StatusDescription)); 38 | } 39 | 40 | [Test] 41 | public void Return_the_http_status_result_when_the_assertion_against_integer_is_true() 42 | { 43 | var expected = _controller.StatusCode(); 44 | var actual = _controller.WithCallTo(c => c.StatusCode()) 45 | .ShouldGiveHttpStatus(ControllerResultTestController.Code); 46 | Assert.That(actual.StatusCode, Is.EqualTo(expected.StatusCode)); 47 | Assert.That(actual.StatusDescription, Is.EqualTo(expected.StatusDescription)); 48 | } 49 | 50 | [Test] 51 | public void Return_the_http_status_result_when_the_assertion_against_status_code_enum_is_true() 52 | { 53 | var expected = _controller.StatusCode(); 54 | var actual = _controller.WithCallTo(c => c.StatusCode()) 55 | .ShouldGiveHttpStatus((HttpStatusCode) ControllerResultTestController.Code); 56 | Assert.That(actual.StatusCode, Is.EqualTo(expected.StatusCode)); 57 | Assert.That(actual.StatusDescription, Is.EqualTo(expected.StatusDescription)); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/ControllerResultTestTests/ShouldRenderViewTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using TestStack.FluentMVCTesting.Tests.TestControllers; 3 | 4 | namespace TestStack.FluentMVCTesting.Tests 5 | { 6 | partial class ControllerResultTestShould 7 | { 8 | [Test] 9 | public void Check_for_default_view_or_partial() 10 | { 11 | _controller.WithCallTo(c => c.DefaultView()).ShouldRenderDefaultView(); 12 | _controller.WithCallTo(c => c.DefaultView()).ShouldRenderView("DefaultView"); 13 | _controller.WithCallTo(c => c.DefaultViewExplicit()).ShouldRenderDefaultView(); 14 | _controller.WithCallTo(c => c.DefaultPartial()).ShouldRenderDefaultPartialView(); 15 | _controller.WithCallTo(c => c.DefaultPartial()).ShouldRenderPartialView("DefaultPartial"); 16 | _controller.WithCallTo(c => c.DefaultPartialExplicit()).ShouldRenderDefaultPartialView(); 17 | } 18 | 19 | [Test] 20 | public void Check_for_invalid_view_name_when_expecting_default_view() 21 | { 22 | var exception = Assert.Throws(() => 23 | _controller.WithCallTo(c => c.RandomView()).ShouldRenderDefaultView() 24 | ); 25 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected result view to be 'RandomView', but instead was given '{0}'.", ControllerResultTestController.RandomViewName))); 26 | } 27 | 28 | [Test] 29 | public void Check_for_invalid_view_name_when_expecting_default_partial() 30 | { 31 | var exception = Assert.Throws(() => 32 | _controller.WithCallTo(c => c.RandomPartial()).ShouldRenderDefaultPartialView() 33 | ); 34 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected result view to be 'RandomPartial', but instead was given '{0}'.", ControllerResultTestController.RandomViewName))); 35 | } 36 | 37 | [Test] 38 | public void Check_for_named_view_or_partial() 39 | { 40 | _controller.WithCallTo(c => c.NamedView()).ShouldRenderView(ControllerResultTestController.ViewName); 41 | _controller.WithCallTo(c => c.NamedPartial()).ShouldRenderPartialView(ControllerResultTestController.PartialName); 42 | } 43 | 44 | [Test] 45 | public void Check_for_invalid_view_name() 46 | { 47 | var exception = Assert.Throws(() => 48 | _controller.WithCallTo(c => c.RandomView()).ShouldRenderView(ControllerResultTestController.ViewName) 49 | ); 50 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected result view to be '{0}', but instead was given '{1}'.", ControllerResultTestController.ViewName, ControllerResultTestController.RandomViewName))); 51 | } 52 | 53 | [Test] 54 | public void Check_for_invalid_partial_name() 55 | { 56 | var exception = Assert.Throws(() => 57 | _controller.WithCallTo(c => c.RandomPartial()).ShouldRenderPartialView(ControllerResultTestController.PartialName) 58 | ); 59 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected result view to be '{0}', but instead was given '{1}'.", ControllerResultTestController.PartialName, ControllerResultTestController.RandomViewName))); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/ControllerResultTestTests/ShouldReturnContentTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using System.Web.Mvc; 3 | using System.Text; 4 | using TestStack.FluentMVCTesting.Tests.TestControllers; 5 | 6 | namespace TestStack.FluentMVCTesting.Tests 7 | { 8 | partial class ControllerResultTestShould 9 | { 10 | [Test] 11 | public void Check_for_content_result() 12 | { 13 | _controller.WithCallTo(c => c.Content()).ShouldReturnContent(); 14 | } 15 | 16 | [Test] 17 | public void Check_for_content_result_and_check_content() 18 | { 19 | _controller.WithCallTo(c => c.Content()).ShouldReturnContent(ControllerResultTestController.TextualContent); 20 | } 21 | 22 | [Test] 23 | public void Check_for_content_result_and_check_invalid_content() 24 | { 25 | const string content = "dummy contents"; 26 | 27 | var exception = Assert.Throws(() => _controller.WithCallTo(c => c.Content()).ShouldReturnContent(content)); 28 | 29 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected content to be '{0}', but instead was '{1}'.", content, ControllerResultTestController.TextualContent))); 30 | } 31 | 32 | [Test] 33 | public void Check_for_content_result_and_check_content_and_check_content_type() 34 | { 35 | _controller.WithCallTo(c => c.Content()).ShouldReturnContent(ControllerResultTestController.TextualContent, ControllerResultTestController.ContentType); 36 | } 37 | 38 | [Test] 39 | public void Check_for_content_result_and_check_content_and_check_invalid_content_type() 40 | { 41 | const string contentType = "application/dummy"; 42 | 43 | var exception = Assert.Throws(() => _controller.WithCallTo(c => c.Content()).ShouldReturnContent(ControllerResultTestController.TextualContent, contentType)); 44 | 45 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected content type to be '{0}', but instead was '{1}'.", contentType, ControllerResultTestController.ContentType))); 46 | } 47 | 48 | [Test] 49 | public void Check_for_content_result_and_check_content_and_check_content_type_and_check_content_encoding() 50 | { 51 | _controller.WithCallTo(c => c.Content()).ShouldReturnContent(ControllerResultTestController.TextualContent, ControllerResultTestController.ContentType, ControllerResultTestController.TextualContentEncoding); 52 | } 53 | 54 | [Test] 55 | public void Check_for_content_result_and_check_content_and_check_content_type_and_check_invalid_content_encoding() 56 | { 57 | var encoding = Encoding.Unicode; 58 | 59 | var exception = Assert.Throws(() => _controller.WithCallTo(c => c.Content()).ShouldReturnContent(ControllerResultTestController.TextualContent, ControllerResultTestController.ContentType, encoding)); 60 | 61 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected encoding to be equal to {0}, but instead was {1}.", encoding.EncodingName, ControllerResultTestController.TextualContentEncoding.EncodingName))); 62 | } 63 | 64 | [Test] 65 | public void Check_for_content_result_and_check_invalid_content_and_check_invalid_content_type_and_check_invalid_encoding() 66 | { 67 | const string contentType = "application/dummy"; 68 | const string content = "dumb"; 69 | Encoding encoding = Encoding.Unicode; 70 | 71 | var exception = Assert.Throws(() => _controller.WithCallTo(c => c.Content()).ShouldReturnContent(content, contentType, encoding)); 72 | 73 | // Assert that the content type validation occurs before that of the actual content. 74 | Assert.That(exception.Message.Contains("content type")); 75 | } 76 | 77 | [Test] 78 | public void Emit_readable_error_message_when_the_actual_content_encoding_has_not_been_specified() 79 | { 80 | var exception = Assert.Throws(() => _controller.WithCallTo(c => c.ContentWithoutEncodingSpecified()).ShouldReturnContent(encoding: ControllerResultTestController.TextualContentEncoding)); 81 | 82 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected encoding to be equal to {0}, but instead was null.", ControllerResultTestController.TextualContentEncoding.EncodingName))); 83 | } 84 | 85 | [Test] 86 | public void Return_the_content_result() 87 | { 88 | var expected = (ContentResult)_controller.Content(); 89 | var actual = _controller.WithCallTo(c => c.Content()) 90 | .ShouldReturnContent(ControllerResultTestController.TextualContent); 91 | Assert.That(actual.Content,Is.EqualTo(expected.Content)); 92 | Assert.That(actual.ContentType, Is.EqualTo(expected.ContentType)); 93 | Assert.That(actual.ContentEncoding, Is.EqualTo(expected.ContentEncoding)); 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/ControllerResultTestTests/ShouldReturnEmptyResultTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace TestStack.FluentMVCTesting.Tests 4 | { 5 | partial class ControllerResultTestShould 6 | { 7 | [Test] 8 | public void Check_for_empty_result() 9 | { 10 | _controller.WithCallTo(c => c.EmptyResult()).ShouldReturnEmptyResult(); 11 | } 12 | 13 | [Test] 14 | public void Return_the_empty_result() 15 | { 16 | var actual = _controller.WithCallTo(c => c.EmptyResult()) 17 | .ShouldReturnEmptyResult(); 18 | Assert.NotNull(actual); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/ControllerResultTestTests/ShouldReturnJsonTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using TestStack.FluentMVCTesting.Tests.TestControllers; 3 | 4 | namespace TestStack.FluentMVCTesting.Tests 5 | { 6 | partial class ControllerResultTestShould 7 | { 8 | [Test] 9 | public void Allow_the_object_that_is_returned_to_be_checked() 10 | { 11 | _controller.WithCallTo(c => c.Json()) 12 | .ShouldReturnJson(d => Assert.That(d, Is.EqualTo(ControllerResultTestController.JsonValue))); 13 | } 14 | 15 | [Test] 16 | public void Return_the_json_result() 17 | { 18 | var expected = _controller.Json(); 19 | var actual = _controller.WithCallTo(c => c.Json()).ShouldReturnJson(); 20 | Assert.That(actual.Data, Is.EqualTo(expected.Data)); 21 | Assert.That(actual.JsonRequestBehavior, Is.EqualTo(expected.JsonRequestBehavior)); 22 | } 23 | 24 | [Test] 25 | public void Return_the_json_result_when_the_assertion_is_true() 26 | { 27 | var expected = _controller.Json(); 28 | var actual =_controller.WithCallTo(c => c.Json()) 29 | .ShouldReturnJson(d => Assert.That(d, Is.EqualTo(ControllerResultTestController.JsonValue))); 30 | Assert.That(actual.Data, Is.EqualTo(expected.Data)); 31 | Assert.That(actual.JsonRequestBehavior, Is.EqualTo(expected.JsonRequestBehavior)); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/ModelErrorTestTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Web.Mvc; 5 | using NSubstitute; 6 | using NUnit.Framework; 7 | 8 | namespace TestStack.FluentMVCTesting.Tests 9 | { 10 | class ModelErrorTestMetadata : Tuple 11 | { 12 | public ModelErrorTestMetadata(string errorMessagePart, string validError1Value, string validError2Value, ModelErrorTestCall testCall) 13 | : base(errorMessagePart, validError1Value, validError2Value, testCall) {} 14 | } 15 | delegate IModelTest ModelErrorTestCall(ModelErrorTest modelErrorTest, string input); 16 | 17 | [TestFixture] 18 | class ModelErrorTestShould 19 | { 20 | // List of test metadata: 21 | // Error message part, valid value for first error, valid value for second error, lambda with method to call 22 | #pragma warning disable 169 23 | private static List _tests = new List 24 | { 25 | Test("to be", Error1, Error2, (t, s) => t.ThatEquals(s)), 26 | Test("to start with", Error1.Substring(0, 3), Error2.Substring(0, 3), (t, s) => t.BeginningWith(s)), 27 | Test("to end with", Error1.Substring(5), Error2.Substring(5), (t, s) => t.EndingWith(s)), 28 | Test("to contain", Error1.Substring(2, 7), Error2.Substring(2, 7), (t, s) => t.Containing(s)), 29 | }; 30 | #pragma warning restore 169 31 | 32 | private static ModelErrorTestMetadata Test(string message, string error1, string error2, ModelErrorTestCall testCall) 33 | { 34 | return new ModelErrorTestMetadata(message, error1, error2, testCall); 35 | } 36 | 37 | private ModelErrorTest _modelErrorTest; 38 | private IModelTest _modelTest; 39 | 40 | private const string ErrorKey = "Key"; 41 | private const string Error1 = "Error message 1"; 42 | private const string Error2 = "Error message 2"; 43 | private const string NonError = "Random error"; 44 | private readonly string _combinedErrors = string.Format("{0}, {1}", Error1, Error2); 45 | private readonly string _initialExceptionMessage = string.Format("Expected error message for key '{0}'", ErrorKey); 46 | private readonly IEnumerable _errors = new[] 47 | { 48 | new ModelError(Error1), 49 | new ModelError(Error2) 50 | }; 51 | 52 | [SetUp] 53 | public void Setup() 54 | { 55 | _modelTest = Substitute.For>(); 56 | _modelErrorTest = new ModelErrorTest(_modelTest, ErrorKey, _errors); 57 | } 58 | 59 | [Test] 60 | [TestCaseSource("_tests")] 61 | public void Check_for_lack_of_matching_error_message(ModelErrorTestMetadata test) 62 | { 63 | var exception = Assert.Throws(() => 64 | test.Item4(_modelErrorTest, NonError) 65 | ); 66 | Assert.That(exception.Message, Is.EqualTo(string.Format("{0} {1} '{2}', but instead found '{3}'.", _initialExceptionMessage, test.Item1, NonError, _combinedErrors))); 67 | } 68 | 69 | [Test] 70 | [TestCaseSource("_tests")] 71 | public void Check_for_first_error_message(ModelErrorTestMetadata test) 72 | { 73 | test.Item4(_modelErrorTest, test.Item2); 74 | } 75 | 76 | [Test] 77 | [TestCaseSource("_tests")] 78 | public void Check_for_subsequent_error_message(ModelErrorTestMetadata test) 79 | { 80 | test.Item4(_modelErrorTest, test.Item3); 81 | } 82 | 83 | [Test] 84 | [TestCaseSource("_tests")] 85 | public void Allow_for_chained_test_calls(ModelErrorTestMetadata test) 86 | { 87 | Assert.That(test.Item4(_modelErrorTest, test.Item2), Is.EqualTo(_modelTest)); 88 | } 89 | 90 | [Test] 91 | public void Chain_call_to_check_model_error_in_property() 92 | { 93 | var returnVal = Substitute.For>(); 94 | _modelTest.AndModelErrorFor(Arg.Any>>()).Returns(returnVal); 95 | 96 | Assert.That(_modelErrorTest.AndModelErrorFor(m => m.Property1), Is.EqualTo(returnVal)); 97 | } 98 | 99 | [Test] 100 | public void Chain_call_to_check_no_model_error_in_property() 101 | { 102 | var returnVal = Substitute.For>(); 103 | _modelTest.AndNoModelErrorFor(Arg.Any>>()).Returns(returnVal); 104 | 105 | Assert.That(_modelErrorTest.AndNoModelErrorFor(m => m.Property1), Is.EqualTo(returnVal)); 106 | } 107 | 108 | [Test] 109 | public void Chain_call_to_check_model_error_by_key() 110 | { 111 | var returnVal = Substitute.For>(); 112 | _modelTest.AndModelError("Key").Returns(returnVal); 113 | 114 | Assert.That(_modelErrorTest.AndModelError("Key"), Is.EqualTo(returnVal)); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/ModelTestTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace TestStack.FluentMVCTesting.Tests 4 | { 5 | [TestFixture] 6 | class ModelTestShould 7 | { 8 | private ModelTest _modelTest; 9 | private ViewTestController _controller; 10 | 11 | [SetUp] 12 | public void Setup() 13 | { 14 | _controller = new ViewTestController(); 15 | _modelTest = new ModelTest(_controller); 16 | } 17 | 18 | [Test] 19 | public void Check_for_lack_of_model_errors() 20 | { 21 | _modelTest.AndNoModelErrors(); 22 | } 23 | 24 | [Test] 25 | public void Check_for_unexpected_model_errors() 26 | { 27 | _controller.ModelState.AddModelError("key", "error"); 28 | var exception = Assert.Throws(() => 29 | _modelTest.AndNoModelErrors() 30 | ); 31 | Assert.That(exception.Message, Is.EqualTo("Expected controller 'ViewTestController' to have no model errors, but it had some.")); 32 | } 33 | 34 | [Test] 35 | public void Check_for_model_error_in_key() 36 | { 37 | _controller.ModelState.AddModelError("Key", "error"); 38 | _modelTest.AndModelError("Key"); 39 | } 40 | 41 | [Test] 42 | public void Check_for_unexpected_lack_of_model_error_in_key() 43 | { 44 | var exception = Assert.Throws(() => 45 | _modelTest.AndModelError("Key") 46 | ); 47 | Assert.That(exception.Message, Is.EqualTo("Expected controller 'ViewTestController' to have a model error against key 'Key', but none found.")); 48 | } 49 | 50 | [Test] 51 | public void Check_for_model_error_in_property() 52 | { 53 | _controller.ModelState.AddModelError("Property1", "error"); 54 | _modelTest.AndModelErrorFor(m => m.Property1); 55 | } 56 | 57 | [Test] 58 | public void Check_for_unexpected_lack_of_model_error_in_property() 59 | { 60 | var exception = Assert.Throws(() => 61 | _modelTest.AndModelErrorFor(m => m.Property1) 62 | ); 63 | Assert.That(exception.Message, Is.EqualTo("Expected controller 'ViewTestController' to have a model error for member 'Property1', but none found.")); 64 | } 65 | 66 | [Test] 67 | public void Check_for_no_model_error_in_property() 68 | { 69 | _modelTest.AndNoModelErrorFor(m => m.Property1); 70 | } 71 | 72 | [Test] 73 | public void Check_for_unexpected_model_error_in_property() 74 | { 75 | _controller.ModelState.AddModelError("Property1", "error"); 76 | var exception = Assert.Throws(() => 77 | _modelTest.AndNoModelErrorFor(m => m.Property1) 78 | ); 79 | Assert.That(exception.Message, Is.EqualTo("Expected controller 'ViewTestController' to have no model errors for member 'Property1', but found some.")); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("TestStack.FluentMVCTesting.Tests")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("TestStack.FluentMVCTesting.Tests")] 12 | [assembly: AssemblyCopyright("Copyright © 2014 TestStack")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("845e8eee-9a7e-4aee-972a-1133d6e5aecd")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/RouteValueDictionaryExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Routing; 2 | using NUnit.Framework; 3 | 4 | namespace TestStack.FluentMVCTesting.Tests 5 | { 6 | [TestFixture] 7 | class RouteValueDictionaryExtensionsTests 8 | { 9 | [Test] 10 | public void WithRouteValue_ThrowsWhenDictIsEmpty() 11 | { 12 | var dict = new RouteValueDictionary(); 13 | 14 | Assert.Throws(() => dict.WithRouteValue("NotImportant")); 15 | } 16 | 17 | [Test] 18 | public void WithRouteValue_ThrowsWhenDictDoesntHaveValue() 19 | { 20 | var dict = new RouteValueDictionary(); 21 | dict.Add("Existing", "NotImportant"); 22 | 23 | Assert.Throws(() => dict.WithRouteValue("NotExisting")); 24 | } 25 | 26 | [Test] 27 | public void WithRouteValue_ThrowsWhenDictHasIncorrectValue() 28 | { 29 | var dict = new RouteValueDictionary(); 30 | dict.Add("Existing", "Correct"); 31 | 32 | Assert.Throws(() => dict.WithRouteValue("Existing", "Incorrect")); 33 | } 34 | 35 | [Test] 36 | public void WithRouteValue_ThrowIfValueTypeMismatch() 37 | { 38 | var dict = new RouteValueDictionary(); 39 | dict.Add("Existing", 1); 40 | 41 | Assert.Throws(() => dict.WithRouteValue("Existing", "1")); 42 | } 43 | 44 | [Test] 45 | public void WithRouteValue_DoesntThrowIfValueIsCorrect() 46 | { 47 | var dict = new RouteValueDictionary(); 48 | dict.Add("Existing", "Correct"); 49 | 50 | dict.WithRouteValue("Existing", "Correct"); 51 | 52 | Assert.Pass(); 53 | } 54 | 55 | [Test] 56 | public void WithRouteValue_CanUseIntType() 57 | { 58 | var dict = new RouteValueDictionary(); 59 | dict.Add("Existing", 10); 60 | 61 | dict.WithRouteValue("Existing", 10); 62 | 63 | Assert.Pass(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/TempDataResultTest.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using NUnit.Framework; 3 | using TestStack.FluentMVCTesting.Tests.TestControllers; 4 | 5 | namespace TestStack.FluentMVCTesting.Tests 6 | { 7 | [TestFixture] 8 | public class TempDataResultTestShould 9 | { 10 | private ControllerExtensionsController _controller; 11 | private TempDataResultTest _tempDataTest; 12 | 13 | [SetUp] 14 | public void Setup() 15 | { 16 | _controller = new ControllerExtensionsController(); 17 | _tempDataTest = new TempDataResultTest(_controller); 18 | } 19 | 20 | [Test] 21 | public void Check_for_existent_temp_data_property() 22 | { 23 | const string key = ""; 24 | _controller.TempData[key] = ""; 25 | 26 | _tempDataTest.AndShouldHaveTempDataProperty(key); 27 | } 28 | 29 | [Test] 30 | public void Check_for_unexpected_non_existent_temp_data_property() 31 | { 32 | const string key = ""; 33 | 34 | var exception = Assert.Throws(() => 35 | _tempDataTest.AndShouldHaveTempDataProperty(key)); 36 | 37 | Assert.That(exception.Message, Is.EqualTo(string.Format( 38 | "Expected TempData to have a non-null value with key '{0}', but none found.", key))); 39 | } 40 | 41 | [Test] 42 | public void Check_for_existent_temp_data_property_and_check_value() 43 | { 44 | const string key = ""; 45 | const int value = 10; 46 | _controller.TempData[key] = value; 47 | 48 | _tempDataTest.AndShouldHaveTempDataProperty(key, value); 49 | } 50 | 51 | [Test] 52 | public void Check_for_existent_temp_data_property_and_check_invalid_value() 53 | { 54 | const string key = ""; 55 | const int actualValue = 0; 56 | const int expectedValue = 1; 57 | _controller.TempData[key] = actualValue; 58 | 59 | var exception = Assert.Throws(() => 60 | _tempDataTest.AndShouldHaveTempDataProperty(key, expectedValue)); 61 | 62 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected value for key '{0}' to be '{1}', but instead found '{2}'", key, expectedValue, actualValue))); 63 | } 64 | 65 | [Test] 66 | public void Check_for_existent_temp_data_property_and_check_invalid_value_of_different_types() 67 | { 68 | const string key = ""; 69 | const int actualValue = 0; 70 | const string expectedValue = "one"; 71 | _controller.TempData[key] = actualValue; 72 | 73 | var exception = Assert.Throws(() => 74 | _tempDataTest.AndShouldHaveTempDataProperty(key, expectedValue)); 75 | 76 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected value to be of type {0}, but instead was {1}.", expectedValue.GetType().FullName, actualValue.GetType().FullName))); 77 | } 78 | 79 | [Test] 80 | public void Check_for_existent_temp_data_property_and_check_value_valid_using_referential_equality() 81 | { 82 | const string key = ""; 83 | MemoryStream expectedValue = new MemoryStream(); 84 | _controller.TempData[key] = expectedValue; 85 | 86 | _tempDataTest.AndShouldHaveTempDataProperty(key, expectedValue); 87 | } 88 | 89 | [Test] 90 | public void Check_for_existent_temp_data_property_and_check_value_using_valid_predicate() 91 | { 92 | const string key = ""; 93 | const int value = 1; 94 | _controller.TempData[key] = value; 95 | 96 | _tempDataTest.AndShouldHaveTempDataProperty(key, x => x == value); 97 | } 98 | 99 | [Test] 100 | public void Check_for_existent_temp_data_property_and_check_value_using_invalid_predicate() 101 | { 102 | const string key = ""; 103 | _controller.TempData[key] = 1; 104 | 105 | var exception = Assert.Throws(() => 106 | _tempDataTest.AndShouldHaveTempDataProperty(key, x => x == 0)); 107 | 108 | Assert.That(exception.Message, Is.EqualTo("Expected view model to pass the given condition, but it failed.")); 109 | } 110 | 111 | [Test] 112 | public void Check_for_non_existent_temp_data_property_when_supplied_with_predicate() 113 | { 114 | const string key = ""; 115 | 116 | var exception = Assert.Throws(() => 117 | _tempDataTest.AndShouldHaveTempDataProperty(key, x => x == 0)); 118 | 119 | Assert.That(exception.Message, Is.EqualTo(string.Format( 120 | "Expected TempData to have a non-null value with key '{0}', but none found.", key))); 121 | } 122 | 123 | [Test] 124 | public void Check_for_non_existent_temp_data_property() 125 | { 126 | _tempDataTest 127 | .AndShouldNotHaveTempDataProperty(""); 128 | } 129 | 130 | [Test] 131 | public void Check_for_unexpected_existent_temp_data_property() 132 | { 133 | const string Key = ""; 134 | _controller.TempData[Key] = ""; 135 | 136 | var exception = Assert.Throws(() => 137 | _tempDataTest.AndShouldNotHaveTempDataProperty(Key)); 138 | 139 | Assert.That(exception.Message, Is.EqualTo(string.Format( 140 | "Expected TempData to have no value with key '{0}', but found one.", Key))); 141 | } 142 | 143 | [Test] 144 | public void Return_the_same_temp_data_result() 145 | { 146 | var actual = _tempDataTest 147 | .AndShouldNotHaveTempDataProperty(""); 148 | Assert.That(actual, Is.SameAs(_tempDataTest)); 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/TestControllers/AsyncController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using System.Web.Mvc; 3 | 4 | namespace TestStack.FluentMVCTesting.Tests.TestControllers 5 | { 6 | class AsyncController : Controller 7 | { 8 | public Task AsyncViewAction() 9 | { 10 | // Task.FromResult would be better, but I want to support .NET 4 11 | return Task.Factory.StartNew(() => View()); 12 | } 13 | 14 | [ChildActionOnly] 15 | public Task AsyncChildViewAction() 16 | { 17 | return Task.Factory.StartNew(() => View()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/TestControllers/ControllerExtensionsController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace TestStack.FluentMVCTesting.Tests.TestControllers 4 | { 5 | class ControllerExtensionsController : Controller 6 | { 7 | public bool SomeActionCalled { get; set; } 8 | public bool SomeChildActionCalled { get; set; } 9 | 10 | public ActionResult SomeAction() 11 | { 12 | SomeActionCalled = true; 13 | return new EmptyResult(); 14 | } 15 | 16 | [ChildActionOnly] 17 | public ActionResult SomeChildAction() 18 | { 19 | SomeChildActionCalled = true; 20 | return new EmptyResult(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/TestStack.FluentMVCTesting.Tests.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/ViewResultTestTests.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | using System.Web.Mvc; 3 | using NUnit.Framework; 4 | 5 | namespace TestStack.FluentMVCTesting.Tests 6 | { 7 | [TestFixture] 8 | class ViewResultTestShould 9 | { 10 | private ViewResultTest _viewResultTest; 11 | private TestViewModel _model; 12 | private ViewResult _viewResult; 13 | 14 | [SetUp] 15 | public void Setup() 16 | { 17 | _viewResult = new ViewResult(); 18 | _model = new TestViewModel { Property1 = "test", Property2 = 3 }; 19 | _viewResult.ViewData.Model = _model; 20 | _viewResultTest = new ViewResultTest(_viewResult, new ViewTestController()); 21 | } 22 | 23 | [Test] 24 | public void Check_the_type_of_model() 25 | { 26 | _viewResultTest.WithModel(); 27 | } 28 | 29 | [Test] 30 | public void Check_for_null_model() 31 | { 32 | _viewResult.ViewData.Model = null; 33 | var exception = Assert.Throws(() => 34 | _viewResultTest.WithModel() 35 | ); 36 | Assert.That(exception.Message, Is.EqualTo("Expected view model, but was null.")); 37 | } 38 | 39 | [Test] 40 | public void Check_for_invalid_model_type() 41 | { 42 | var exception = Assert.Throws(() => 43 | _viewResultTest.WithModel() 44 | ); 45 | Assert.That(exception.Message, Is.EqualTo("Expected view model to be of type 'InvalidViewModel', but it is actually of type 'TestViewModel'.")); 46 | } 47 | 48 | [Test] 49 | public void Check_for_model_by_reference() 50 | { 51 | _viewResultTest.WithModel(_model); 52 | } 53 | 54 | [Test] 55 | public void Check_for_invalid_model_by_reference() 56 | { 57 | var exception = Assert.Throws(() => 58 | _viewResultTest.WithModel(new TestViewModel()) 59 | ); 60 | Assert.That(exception.Message, Is.EqualTo("Expected view model to be the given model, but in fact it was a different model.")); 61 | } 62 | 63 | [Test] 64 | public void Check_for_model_using_predicate() 65 | { 66 | _viewResultTest.WithModel(m => m.Property1 == _model.Property1 && m.Property2 == _model.Property2); 67 | } 68 | 69 | [Test] 70 | public void Check_for_invalid_model_using_predicate() 71 | { 72 | var exception = Assert.Throws(() => 73 | _viewResultTest.WithModel(m => m.Property1 == null) 74 | ); 75 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected view model {{\"Property1\":\"{0}\",\"Property2\":{1}}} to pass the given condition ((m) => (m.Property1 == null)), but it failed.", _model.Property1, _model.Property2))); 76 | } 77 | 78 | [Test] 79 | public void Check_for_invalid_model_using_predicate_with_conditional_or() 80 | { 81 | var exception = Assert.Throws(() => 82 | _viewResultTest.WithModel(m => m.Property1 == null || m.Property2 == 1) 83 | ); 84 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected view model {{\"Property1\":\"{0}\",\"Property2\":{1}}} to pass the given condition ((m) => ((m.Property1 == null) || (m.Property2 == 1))), but it failed.", _model.Property1, _model.Property2))); 85 | } 86 | 87 | [Test] 88 | public void Check_for_invalid_model_using_predicate_with_primitive_operand() 89 | { 90 | _viewResult.ViewData.Model = "abc"; 91 | var exception = Assert.Throws(() => 92 | _viewResultTest.WithModel(m => m == "ab") 93 | ); 94 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected view model \"{0}\" to pass the given condition ((m) => (m == \"ab\")), but it failed.", _viewResult.ViewData.Model))); 95 | } 96 | 97 | [Test] 98 | public void Check_for_invalid_model_using_predicate_with_captured_var_operand() 99 | { 100 | var capturedOuterVar = "ab"; 101 | _viewResult.ViewData.Model = "abc"; 102 | var exception = Assert.Throws(() => 103 | _viewResultTest.WithModel(m => m == capturedOuterVar) 104 | ); 105 | Assert.That(exception.Message, Is.EqualTo(string.Format("Expected view model \"{0}\" to pass the given condition ((m) => (m == capturedOuterVar)), but it failed.", _viewResult.ViewData.Model))); 106 | } 107 | 108 | [Test] 109 | public void Allow_for_assertions_on_the_model() 110 | { 111 | _viewResultTest.WithModel(m => 112 | { 113 | Assert.That(m.Property1, Is.EqualTo(_model.Property1)); 114 | Assert.That(m.Property2, Is.EqualTo(_model.Property2)); 115 | } 116 | ); 117 | } 118 | 119 | [Test] 120 | public void Run_any_assertions_on_the_model() 121 | { 122 | Assert.Throws(() => 123 | _viewResultTest.WithModel(m => Assert.That(m.Property1, Is.Null)) 124 | ); 125 | } 126 | } 127 | 128 | class InvalidViewModel { } 129 | public class TestViewModel 130 | { 131 | public string Property1 { get; set; } 132 | public int Property2 { get; set; } 133 | } 134 | class ViewTestController : Controller { } 135 | } 136 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TestStack.FluentMVCTesting.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.30501.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStack.FluentMVCTesting", "TestStack.FluentMVCTesting\TestStack.FluentMVCTesting.csproj", "{152CA00F-18D3-4CF5-8CA0-2C5B70CBEA19}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStack.FluentMVCTesting.Tests", "TestStack.FluentMVCTesting.Tests\TestStack.FluentMVCTesting.Tests.csproj", "{4DCC907C-A08A-4139-BB6B-2D34B21F318B}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStack.FluentMVCTesting.Mvc3", "TestStack.FluentMVCTesting.Mvc3\TestStack.FluentMVCTesting.Mvc3.csproj", "{17E643B6-0448-4E6F-A8D8-D726154D73E1}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution Files", "{21EA5DD6-9360-4966-AE7C-FC2329AAE01F}" 13 | ProjectSection(SolutionItems) = preProject 14 | LICENSE = LICENSE 15 | logo.png = logo.png 16 | README.md = README.md 17 | EndProjectSection 18 | EndProject 19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{46E90596-A670-4D0B-B036-C7859573C89E}" 20 | EndProject 21 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStack.FluentMVCTesting.Sample.Tests", "Samples\TestStack.FluentMVCTesting.Sample.Tests\TestStack.FluentMVCTesting.Sample.Tests.csproj", "{F36BC506-1076-49BF-A1A4-A76D6560AA64}" 22 | EndProject 23 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OldMvc", "OldMvc", "{9E15A69C-A0BA-43DF-94EB-9465C5D1BD61}" 24 | EndProject 25 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStack.FluentMVCTesting.Mvc3.Tests", "TestStack.FluentMVCTesting.Mvc3.Tests\TestStack.FluentMVCTesting.Mvc3.Tests.csproj", "{F6A48378-7254-4B72-A02B-5E1023533A1B}" 26 | EndProject 27 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStack.FluentMVCTesting.Mvc4", "TestStack.FluentMVCTesting.Mvc4\TestStack.FluentMVCTesting.Mvc4.csproj", "{BF71218D-3E60-4146-BDF5-DA15EF29F0AA}" 28 | EndProject 29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStack.FluentMVCTesting.Mvc4.Tests", "TestStack.FluentMVCTesting.Mvc4.Tests\TestStack.FluentMVCTesting.Mvc4.Tests.csproj", "{5264EC40-E039-4634-B92D-79AD3656A23E}" 30 | EndProject 31 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStack.FluentMVCTesting.Sample", "Samples\TestStack.FluentMVCTesting.Sample\TestStack.FluentMVCTesting.Sample.csproj", "{FD292B9E-1493-428F-8AF6-F7CF9CF463C5}" 32 | EndProject 33 | Global 34 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 35 | Debug|Any CPU = Debug|Any CPU 36 | Release|Any CPU = Release|Any CPU 37 | EndGlobalSection 38 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 39 | {152CA00F-18D3-4CF5-8CA0-2C5B70CBEA19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 40 | {152CA00F-18D3-4CF5-8CA0-2C5B70CBEA19}.Debug|Any CPU.Build.0 = Debug|Any CPU 41 | {152CA00F-18D3-4CF5-8CA0-2C5B70CBEA19}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {152CA00F-18D3-4CF5-8CA0-2C5B70CBEA19}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {4DCC907C-A08A-4139-BB6B-2D34B21F318B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {4DCC907C-A08A-4139-BB6B-2D34B21F318B}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {4DCC907C-A08A-4139-BB6B-2D34B21F318B}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {4DCC907C-A08A-4139-BB6B-2D34B21F318B}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {17E643B6-0448-4E6F-A8D8-D726154D73E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 48 | {17E643B6-0448-4E6F-A8D8-D726154D73E1}.Debug|Any CPU.Build.0 = Debug|Any CPU 49 | {17E643B6-0448-4E6F-A8D8-D726154D73E1}.Release|Any CPU.ActiveCfg = Release|Any CPU 50 | {17E643B6-0448-4E6F-A8D8-D726154D73E1}.Release|Any CPU.Build.0 = Release|Any CPU 51 | {F36BC506-1076-49BF-A1A4-A76D6560AA64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {F36BC506-1076-49BF-A1A4-A76D6560AA64}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {F36BC506-1076-49BF-A1A4-A76D6560AA64}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {F36BC506-1076-49BF-A1A4-A76D6560AA64}.Release|Any CPU.Build.0 = Release|Any CPU 55 | {F6A48378-7254-4B72-A02B-5E1023533A1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 56 | {F6A48378-7254-4B72-A02B-5E1023533A1B}.Debug|Any CPU.Build.0 = Debug|Any CPU 57 | {F6A48378-7254-4B72-A02B-5E1023533A1B}.Release|Any CPU.ActiveCfg = Release|Any CPU 58 | {F6A48378-7254-4B72-A02B-5E1023533A1B}.Release|Any CPU.Build.0 = Release|Any CPU 59 | {BF71218D-3E60-4146-BDF5-DA15EF29F0AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 60 | {BF71218D-3E60-4146-BDF5-DA15EF29F0AA}.Debug|Any CPU.Build.0 = Debug|Any CPU 61 | {BF71218D-3E60-4146-BDF5-DA15EF29F0AA}.Release|Any CPU.ActiveCfg = Release|Any CPU 62 | {BF71218D-3E60-4146-BDF5-DA15EF29F0AA}.Release|Any CPU.Build.0 = Release|Any CPU 63 | {5264EC40-E039-4634-B92D-79AD3656A23E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 64 | {5264EC40-E039-4634-B92D-79AD3656A23E}.Debug|Any CPU.Build.0 = Debug|Any CPU 65 | {5264EC40-E039-4634-B92D-79AD3656A23E}.Release|Any CPU.ActiveCfg = Release|Any CPU 66 | {5264EC40-E039-4634-B92D-79AD3656A23E}.Release|Any CPU.Build.0 = Release|Any CPU 67 | {FD292B9E-1493-428F-8AF6-F7CF9CF463C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 68 | {FD292B9E-1493-428F-8AF6-F7CF9CF463C5}.Debug|Any CPU.Build.0 = Debug|Any CPU 69 | {FD292B9E-1493-428F-8AF6-F7CF9CF463C5}.Release|Any CPU.ActiveCfg = Release|Any CPU 70 | {FD292B9E-1493-428F-8AF6-F7CF9CF463C5}.Release|Any CPU.Build.0 = Release|Any CPU 71 | EndGlobalSection 72 | GlobalSection(SolutionProperties) = preSolution 73 | HideSolutionNode = FALSE 74 | EndGlobalSection 75 | GlobalSection(NestedProjects) = preSolution 76 | {17E643B6-0448-4E6F-A8D8-D726154D73E1} = {9E15A69C-A0BA-43DF-94EB-9465C5D1BD61} 77 | {F36BC506-1076-49BF-A1A4-A76D6560AA64} = {46E90596-A670-4D0B-B036-C7859573C89E} 78 | {F6A48378-7254-4B72-A02B-5E1023533A1B} = {9E15A69C-A0BA-43DF-94EB-9465C5D1BD61} 79 | {BF71218D-3E60-4146-BDF5-DA15EF29F0AA} = {9E15A69C-A0BA-43DF-94EB-9465C5D1BD61} 80 | {5264EC40-E039-4634-B92D-79AD3656A23E} = {9E15A69C-A0BA-43DF-94EB-9465C5D1BD61} 81 | {FD292B9E-1493-428F-8AF6-F7CF9CF463C5} = {46E90596-A670-4D0B-B036-C7859573C89E} 82 | EndGlobalSection 83 | EndGlobal 84 | -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ControllerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using System.Threading.Tasks; 4 | using System.Web.Mvc; 5 | 6 | namespace TestStack.FluentMVCTesting 7 | { 8 | public static class ControllerExtensions 9 | { 10 | 11 | public static T WithModelErrors(this T controller) where T : Controller 12 | { 13 | controller.ModelState.AddModelError("Key", "Value"); 14 | return controller; 15 | } 16 | 17 | public static ControllerResultTest WithCallTo(this T controller, Expression> actionCall) 18 | where T : Controller 19 | where TAction : ActionResult 20 | { 21 | var actionName = ((MethodCallExpression)actionCall.Body).Method.Name; 22 | 23 | var actionResult = actionCall.Compile().Invoke(controller); 24 | 25 | return new ControllerResultTest(controller, actionName, actionResult); 26 | } 27 | 28 | public static ControllerResultTest WithCallTo(this T controller, Expression>> actionCall) 29 | where T : Controller 30 | where TAction : ActionResult 31 | { 32 | var actionName = ((MethodCallExpression)actionCall.Body).Method.Name; 33 | 34 | var actionResult = actionCall.Compile().Invoke(controller).Result; 35 | 36 | return new ControllerResultTest(controller, actionName, actionResult); 37 | } 38 | 39 | public static ControllerResultTest WithCallToChild(this T controller, Expression> actionCall) 40 | where T : Controller 41 | where TAction : ActionResult 42 | { 43 | var action = ((MethodCallExpression)actionCall.Body).Method; 44 | 45 | if (!action.IsDefined(typeof(ChildActionOnlyAttribute), false)) 46 | throw new InvalidControllerActionException(string.Format("Expected action {0} of controller {1} to be a child action, but it didn't have the ChildActionOnly attribute.", action.Name, controller.GetType().Name)); 47 | 48 | return controller.WithCallTo(actionCall); 49 | } 50 | 51 | public static ControllerResultTest WithCallToChild(this T controller, Expression>> actionCall) 52 | where T : Controller 53 | where TAction : ActionResult 54 | { 55 | var action = ((MethodCallExpression)actionCall.Body).Method; 56 | 57 | if (!action.IsDefined(typeof(ChildActionOnlyAttribute), false)) 58 | throw new InvalidControllerActionException(string.Format("Expected action {0} of controller {1} to be a child action, but it didn't have the ChildActionOnly attribute.", action.Name, controller.GetType().Name)); 59 | 60 | return controller.WithCallTo(actionCall); 61 | } 62 | 63 | public static TempDataResultTest ShouldHaveTempDataProperty(this ControllerBase controller, string key, object value = null) 64 | { 65 | var actual = controller.TempData[key]; 66 | 67 | if (actual == null) 68 | { 69 | throw new TempDataAssertionException(string.Format( 70 | "Expected TempData to have a non-null value with key '{0}', but none found.", key)); 71 | } 72 | 73 | if (value != null && actual.GetType() != value.GetType()) 74 | { 75 | throw new TempDataAssertionException(string.Format( 76 | "Expected value to be of type {0}, but instead was {1}.", 77 | value.GetType().FullName, 78 | actual.GetType().FullName)); 79 | } 80 | 81 | if (value != null && !value.Equals(actual)) 82 | { 83 | throw new TempDataAssertionException(string.Format( 84 | "Expected value for key '{0}' to be '{1}', but instead found '{2}'", key, value, actual)); 85 | } 86 | 87 | return new TempDataResultTest(controller); 88 | } 89 | 90 | public static TempDataResultTest ShouldHaveTempDataProperty(this ControllerBase controller, string key, Func predicate) 91 | { 92 | var actual = controller.TempData[key]; 93 | 94 | if (actual == null) 95 | { 96 | throw new TempDataAssertionException(string.Format( 97 | "Expected TempData to have a non-null value with key '{0}', but none found.", key)); 98 | } 99 | 100 | if (!predicate((TValue)actual)) 101 | { 102 | throw new TempDataAssertionException("Expected view model to pass the given condition, but it failed."); 103 | } 104 | 105 | return new TempDataResultTest(controller); 106 | } 107 | 108 | public static TempDataResultTest ShouldNotHaveTempDataProperty(this ControllerBase controller, string key) 109 | { 110 | var actual = controller.TempData[key]; 111 | 112 | if (actual != null) 113 | { 114 | throw new TempDataAssertionException(string.Format( 115 | "Expected TempData to have no value with key '{0}', but found one.", key)); 116 | } 117 | 118 | return new TempDataResultTest(controller); 119 | } 120 | 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ControllerResultTest/ControllerResultTest.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace TestStack.FluentMVCTesting 4 | { 5 | public partial class ControllerResultTest where T : Controller 6 | { 7 | public T Controller { get; private set; } 8 | public string ActionName { get; private set; } 9 | public ActionResult ActionResult { get; private set; } 10 | 11 | public void ValidateActionReturnType() where TActionResult : ActionResult 12 | { 13 | var castedActionResult = ActionResult as TActionResult; 14 | 15 | if (ActionResult == null) 16 | throw new ActionResultAssertionException(string.Format("Received null action result when expecting {0}.", typeof(TActionResult).Name)); 17 | 18 | if (castedActionResult == null) 19 | throw new ActionResultAssertionException( 20 | string.Format("Expected action result to be a {0}, but instead received a {1}.", 21 | typeof(TActionResult).Name, ActionResult.GetType().Name 22 | ) 23 | ); 24 | } 25 | 26 | public ControllerResultTest(T controller, string actionName, ActionResult actionResult) 27 | { 28 | Controller = controller; 29 | ActionName = actionName; 30 | ActionResult = actionResult; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ControllerResultTest/ShouldGiveHttpStatus.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Web.Mvc; 3 | 4 | namespace TestStack.FluentMVCTesting 5 | { 6 | public partial class ControllerResultTest 7 | { 8 | public HttpStatusCodeResult ShouldGiveHttpStatus() 9 | { 10 | ValidateActionReturnType(); 11 | return (HttpStatusCodeResult) ActionResult; 12 | } 13 | 14 | public HttpStatusCodeResult ShouldGiveHttpStatus(int status) 15 | { 16 | ValidateActionReturnType(); 17 | 18 | var statusCodeResult = (HttpStatusCodeResult)ActionResult; 19 | 20 | if (statusCodeResult.StatusCode != status) 21 | throw new ActionResultAssertionException(string.Format("Expected HTTP status code to be '{0}', but instead received a '{1}'.", status, statusCodeResult.StatusCode)); 22 | return (HttpStatusCodeResult) ActionResult; 23 | } 24 | 25 | public HttpStatusCodeResult ShouldGiveHttpStatus(HttpStatusCode status) 26 | { 27 | ShouldGiveHttpStatus((int)status); 28 | return (HttpStatusCodeResult)ActionResult; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ControllerResultTest/ShouldRenderFile.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Text; 4 | using System.Web.Mvc; 5 | 6 | namespace TestStack.FluentMVCTesting 7 | { 8 | public partial class ControllerResultTest 9 | { 10 | private static void EnsureContentTypeIsSame(string actual, string expected) 11 | { 12 | if (expected == null) return; 13 | if (actual != expected) 14 | { 15 | throw new ActionResultAssertionException(string.Format( 16 | "Expected file to be of content type '{0}', but instead was given '{1}'.", expected, actual)); 17 | } 18 | } 19 | 20 | private static byte[] ConvertStreamToArray(Stream stream) 21 | { 22 | using (var memoryStream = new MemoryStream()) 23 | { 24 | stream.CopyTo(memoryStream); 25 | stream.Position = 0; 26 | return memoryStream.ToArray(); 27 | } 28 | } 29 | 30 | public FileResult ShouldRenderAnyFile(string contentType = null) 31 | { 32 | ValidateActionReturnType(); 33 | var fileResult = (FileResult)ActionResult; 34 | 35 | EnsureContentTypeIsSame(fileResult.ContentType, contentType); 36 | 37 | return fileResult; 38 | } 39 | 40 | public FileContentResult ShouldRenderFileContents(byte[] contents = null, string contentType = null) 41 | { 42 | ValidateActionReturnType(); 43 | var fileResult = (FileContentResult)ActionResult; 44 | 45 | EnsureContentTypeIsSame(fileResult.ContentType, contentType); 46 | 47 | if (contents != null && !fileResult.FileContents.SequenceEqual(contents)) 48 | { 49 | throw new ActionResultAssertionException(string.Format( 50 | "Expected file contents to be equal to [{0}], but instead was given [{1}].", 51 | string.Join(", ", contents), 52 | string.Join(", ", fileResult.FileContents))); 53 | } 54 | 55 | return fileResult; 56 | } 57 | 58 | public FileContentResult ShouldRenderFileContents(string contents, string contentType = null, Encoding encoding = null) 59 | { 60 | ValidateActionReturnType(); 61 | var fileResult = (FileContentResult)ActionResult; 62 | 63 | EnsureContentTypeIsSame(fileResult.ContentType, contentType); 64 | 65 | if (encoding == null) 66 | encoding = Encoding.UTF8; 67 | 68 | var reconstitutedText = encoding.GetString(fileResult.FileContents); 69 | if (contents != reconstitutedText) 70 | { 71 | throw new ActionResultAssertionException(string.Format( 72 | "Expected file contents to be '{0}', but instead was '{1}'.", 73 | contents, 74 | reconstitutedText)); 75 | } 76 | 77 | return fileResult; 78 | } 79 | 80 | public FileStreamResult ShouldRenderFileStream(byte[] content, string contentType = null) 81 | { 82 | var reconstitutedStream = new MemoryStream(content); 83 | return ShouldRenderFileStream(reconstitutedStream, contentType); 84 | } 85 | 86 | public FileStreamResult ShouldRenderFileStream(Stream stream = null, string contentType = null) 87 | { 88 | ValidateActionReturnType(); 89 | var fileResult = (FileStreamResult)ActionResult; 90 | 91 | EnsureContentTypeIsSame(fileResult.ContentType, contentType); 92 | 93 | if (stream != null) 94 | { 95 | byte[] expected = ConvertStreamToArray(stream); 96 | byte[] actual = ConvertStreamToArray(fileResult.FileStream); 97 | 98 | if (!expected.SequenceEqual(actual)) 99 | { 100 | throw new ActionResultAssertionException(string.Format( 101 | "Expected file contents to be equal to [{0}], but instead was given [{1}].", 102 | string.Join(", ", expected), 103 | string.Join(", ", actual))); 104 | } 105 | } 106 | 107 | return fileResult; 108 | } 109 | 110 | public FileStreamResult ShouldRenderFileStream(string contents, string contentType = null, Encoding encoding = null) 111 | { 112 | ValidateActionReturnType(); 113 | var fileResult = (FileStreamResult)ActionResult; 114 | 115 | EnsureContentTypeIsSame(fileResult.ContentType, contentType); 116 | 117 | if (encoding == null) 118 | encoding = Encoding.UTF8; 119 | 120 | var reconstitutedText = encoding.GetString(ConvertStreamToArray(fileResult.FileStream)); 121 | if (contents != reconstitutedText) 122 | { 123 | throw new ActionResultAssertionException(string.Format( 124 | "Expected file contents to be '{0}', but instead was '{1}'.", 125 | contents, 126 | reconstitutedText)); 127 | } 128 | 129 | return fileResult; 130 | } 131 | 132 | public FilePathResult ShouldRenderFilePath(string fileName = null, string contentType = null) 133 | { 134 | ValidateActionReturnType(); 135 | var fileResult = (FilePathResult)ActionResult; 136 | 137 | EnsureContentTypeIsSame(fileResult.ContentType, contentType); 138 | 139 | if (fileName != null && fileName != fileResult.FileName) 140 | { 141 | throw new ActionResultAssertionException(string.Format( 142 | "Expected file name to be '{0}', but instead was given '{1}'.", 143 | fileName, 144 | fileResult.FileName)); 145 | } 146 | 147 | return fileResult; 148 | } 149 | } 150 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ControllerResultTest/ShouldRenderView.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace TestStack.FluentMVCTesting 4 | { 5 | public partial class ControllerResultTest 6 | { 7 | private ViewResultTest ShouldRenderViewResult(string viewName) where TViewResult : ViewResultBase 8 | { 9 | ValidateActionReturnType(); 10 | 11 | var viewResult = (TViewResult)ActionResult; 12 | 13 | if (viewResult.ViewName != viewName && (viewName != ActionName || viewResult.ViewName != "")) 14 | { 15 | throw new ActionResultAssertionException(string.Format("Expected result view to be '{0}', but instead was given '{1}'.", viewName, viewResult.ViewName == "" ? ActionName : viewResult.ViewName)); 16 | } 17 | 18 | return new ViewResultTest(viewResult, Controller); 19 | } 20 | 21 | public ViewResultTest ShouldRenderView(string viewName) 22 | { 23 | return ShouldRenderViewResult(viewName); 24 | } 25 | 26 | public ViewResultTest ShouldRenderPartialView(string viewName) 27 | { 28 | return ShouldRenderViewResult(viewName); 29 | } 30 | 31 | public ViewResultTest ShouldRenderDefaultView() 32 | { 33 | return ShouldRenderView(ActionName); 34 | } 35 | 36 | public ViewResultTest ShouldRenderDefaultPartialView() 37 | { 38 | return ShouldRenderPartialView(ActionName); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ControllerResultTest/ShouldReturnContent.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Web.Mvc; 3 | 4 | namespace TestStack.FluentMVCTesting 5 | { 6 | public partial class ControllerResultTest 7 | { 8 | public ContentResult ShouldReturnContent(string content = null, string contentType = null, Encoding encoding = null) 9 | { 10 | ValidateActionReturnType(); 11 | var contentResult = (ContentResult)ActionResult; 12 | 13 | if (contentType != null && contentType != contentResult.ContentType) 14 | { 15 | throw new ActionResultAssertionException(string.Format( 16 | "Expected content type to be '{0}', but instead was '{1}'.", 17 | contentType, 18 | contentResult.ContentType)); 19 | } 20 | 21 | if (content != null && content != contentResult.Content) 22 | { 23 | throw new ActionResultAssertionException(string.Format( 24 | "Expected content to be '{0}', but instead was '{1}'.", 25 | content, 26 | contentResult.Content)); 27 | } 28 | 29 | if (encoding != null && encoding != contentResult.ContentEncoding) 30 | { 31 | throw new ActionResultAssertionException(string.Format( 32 | "Expected encoding to be equal to {0}, but instead was {1}.", 33 | encoding.EncodingName, 34 | contentResult.ContentEncoding != null ? contentResult.ContentEncoding.EncodingName : "null")); 35 | } 36 | 37 | return contentResult; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ControllerResultTest/ShouldReturnEmptyResult.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace TestStack.FluentMVCTesting 4 | { 5 | public partial class ControllerResultTest 6 | { 7 | public EmptyResult ShouldReturnEmptyResult() 8 | { 9 | ValidateActionReturnType(); 10 | return (EmptyResult) ActionResult; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ControllerResultTest/ShouldReturnJson.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | 4 | namespace TestStack.FluentMVCTesting 5 | { 6 | public partial class ControllerResultTest 7 | { 8 | public JsonResult ShouldReturnJson() 9 | { 10 | ValidateActionReturnType(); 11 | return (JsonResult) ActionResult; 12 | } 13 | 14 | public JsonResult ShouldReturnJson(Action assertion) 15 | { 16 | ValidateActionReturnType(); 17 | var jsonResult = (JsonResult)ActionResult; 18 | assertion(jsonResult.Data); 19 | return (JsonResult)ActionResult; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/Exceptions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TestStack.FluentMVCTesting 4 | { 5 | public class TempDataAssertionException : Exception 6 | { 7 | public TempDataAssertionException(string message) : base(message) { } 8 | } 9 | 10 | public class ActionResultAssertionException : Exception 11 | { 12 | public ActionResultAssertionException(string message) : base(message) { } 13 | } 14 | 15 | public class ViewResultModelAssertionException : Exception 16 | { 17 | public ViewResultModelAssertionException(string message) : base(message) { } 18 | } 19 | 20 | public class ModelErrorAssertionException : Exception 21 | { 22 | public ModelErrorAssertionException(string message) : base(message) { } 23 | } 24 | 25 | public class InvalidControllerActionException : Exception 26 | { 27 | public InvalidControllerActionException(string message) : base(message) { } 28 | } 29 | 30 | public class InvalidRouteValueException : Exception 31 | { 32 | public InvalidRouteValueException(string message) : base(message) { } 33 | } 34 | 35 | public class MissingRouteValueException : Exception 36 | { 37 | public MissingRouteValueException(string message) : base(message) { } 38 | } 39 | 40 | public class ValueTypeMismatchException : Exception 41 | { 42 | public ValueTypeMismatchException(string message) : base(message) { } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ModelErrorTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Web.Mvc; 6 | 7 | namespace TestStack.FluentMVCTesting 8 | { 9 | public interface IModelErrorTest 10 | { 11 | IModelTest ThatEquals(string errorMessage); 12 | IModelTest BeginningWith(string beginMessage); 13 | IModelTest EndingWith(string endMessage); 14 | IModelTest Containing(string containsMessage); 15 | IModelErrorTest AndModelErrorFor(Expression> memberWithError); 16 | IModelTest AndNoModelErrorFor(Expression> memberWithNoError); 17 | IModelErrorTest AndModelError(string errorKey); 18 | } 19 | 20 | public class ModelErrorTest : IModelErrorTest 21 | { 22 | private readonly IModelTest _modelTest; 23 | private readonly string _errorKey; 24 | private readonly List _errors; 25 | 26 | public ModelErrorTest(IModelTest modelTest, string errorKey, IEnumerable errors) 27 | { 28 | _modelTest = modelTest; 29 | _errorKey = errorKey; 30 | _errors = errors.Select(e => e.ErrorMessage).ToList(); 31 | } 32 | 33 | public IModelTest ThatEquals(string errorMessage) 34 | { 35 | if (!_errors.Any(e => e == errorMessage)) 36 | { 37 | throw new ModelErrorAssertionException(string.Format("Expected error message for key '{0}' to be '{1}', but instead found '{2}'.", _errorKey, errorMessage, string.Join(", ", _errors))); 38 | } 39 | return _modelTest; 40 | } 41 | 42 | public IModelTest BeginningWith(string beginMessage) 43 | { 44 | if (!_errors.Any(e => e.StartsWith(beginMessage))) 45 | { 46 | throw new ModelErrorAssertionException(string.Format("Expected error message for key '{0}' to start with '{1}', but instead found '{2}'.", _errorKey, beginMessage, string.Join(", ", _errors))); 47 | } 48 | return _modelTest; 49 | } 50 | 51 | public IModelTest EndingWith(string endMessage) 52 | { 53 | if (!_errors.Any(e => e.EndsWith(endMessage))) 54 | { 55 | throw new ModelErrorAssertionException(string.Format("Expected error message for key '{0}' to end with '{1}', but instead found '{2}'.", _errorKey, endMessage, string.Join(", ", _errors))); 56 | } 57 | return _modelTest; 58 | } 59 | 60 | public IModelTest Containing(string containsMessage) 61 | { 62 | if (!_errors.Any(e => e.Contains(containsMessage))) 63 | { 64 | throw new ModelErrorAssertionException(string.Format("Expected error message for key '{0}' to contain '{1}', but instead found '{2}'.", _errorKey, containsMessage, string.Join(", ", _errors))); 65 | } 66 | return _modelTest; 67 | } 68 | 69 | public IModelErrorTest AndModelErrorFor(Expression> memberWithError) 70 | { 71 | return _modelTest.AndModelErrorFor(memberWithError); 72 | } 73 | 74 | public IModelErrorTest AndModelError(string errorKey) 75 | { 76 | return _modelTest.AndModelError(errorKey); 77 | } 78 | 79 | public IModelTest AndNoModelErrorFor(Expression> memberWithNoError) 80 | { 81 | return _modelTest.AndNoModelErrorFor(memberWithNoError); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ModelTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using System.Web.Mvc; 4 | 5 | namespace TestStack.FluentMVCTesting 6 | { 7 | public interface IModelTest 8 | { 9 | IModelErrorTest AndModelErrorFor(Expression> memberWithError); 10 | IModelTest AndNoModelErrorFor(Expression> memberWithNoError); 11 | IModelErrorTest AndModelError(string errorKey); 12 | void AndNoModelErrors(); 13 | } 14 | 15 | public class ModelTest : IModelTest 16 | { 17 | private readonly Controller _controller; 18 | 19 | public ModelTest(Controller controller) 20 | { 21 | _controller = controller; 22 | } 23 | 24 | public IModelErrorTest AndModelErrorFor(Expression> memberWithError) 25 | { 26 | var member = ((MemberExpression)memberWithError.Body).Member.Name; 27 | if (!_controller.ModelState.ContainsKey(member) || _controller.ModelState[member].Errors.Count == 0) 28 | throw new ViewResultModelAssertionException(string.Format("Expected controller '{0}' to have a model error for member '{1}', but none found.", _controller.GetType().Name, member)); 29 | return new ModelErrorTest(this, member, _controller.ModelState[member].Errors); 30 | } 31 | 32 | public IModelTest AndNoModelErrorFor(Expression> memberWithNoError) 33 | { 34 | var member = ((MemberExpression)memberWithNoError.Body).Member.Name; 35 | if (_controller.ModelState.ContainsKey(member)) 36 | throw new ViewResultModelAssertionException(string.Format("Expected controller '{0}' to have no model errors for member '{1}', but found some.", _controller.GetType().Name, member)); 37 | return this; 38 | } 39 | 40 | public IModelErrorTest AndModelError(string errorKey) 41 | { 42 | if (!_controller.ModelState.ContainsKey(errorKey) || _controller.ModelState[errorKey].Errors.Count == 0) 43 | throw new ViewResultModelAssertionException(string.Format("Expected controller '{0}' to have a model error against key '{1}', but none found.", _controller.GetType().Name, errorKey)); 44 | return new ModelErrorTest(this, errorKey, _controller.ModelState[errorKey].Errors); 45 | } 46 | 47 | public void AndNoModelErrors() 48 | { 49 | if (!_controller.ModelState.IsValid) 50 | throw new ViewResultModelAssertionException(string.Format("Expected controller '{0}' to have no model errors, but it had some.", _controller.GetType().Name)); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("TestStack.FluentMVCTesting")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TestStack.FluentMVCTesting")] 13 | [assembly: AssemblyCopyright("Copyright © 2014 TestStack")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f53e0b72-ba9c-4670-97de-6241b7b783ea")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/RouteValueDictionaryExtension.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Routing; 2 | 3 | namespace TestStack.FluentMVCTesting 4 | { 5 | public static class RouteValueDictionaryExtension 6 | { 7 | public static RouteValueDictionary WithRouteValue(this RouteValueDictionary dict, string key) 8 | { 9 | if (!dict.ContainsKey(key)) 10 | { 11 | throw new MissingRouteValueException(string.Format("No value {0} in the route dictionary", key)); 12 | } 13 | 14 | return dict; 15 | } 16 | 17 | public static RouteValueDictionary WithRouteValue(this RouteValueDictionary dict, string key, T value) 18 | { 19 | dict.WithRouteValue(key); 20 | 21 | var actualValue = dict[key]; 22 | 23 | if (!(actualValue is T)) 24 | { 25 | throw new ValueTypeMismatchException(string.Format("Invalid type of Value with key {0} \r\n expected {1} \r\n but got {2}", key, value.GetType(), actualValue.GetType())); 26 | } 27 | 28 | if (!Equals(actualValue, value)) 29 | { 30 | throw new InvalidRouteValueException(string.Format("Invalid value for key {0} \r\n expected {1} \r\n but got {2} in the route dictionary",key ,value, actualValue)); 31 | } 32 | 33 | return dict; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/TempDataResultTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Mvc; 3 | 4 | namespace TestStack.FluentMVCTesting 5 | { 6 | public class TempDataResultTest 7 | { 8 | private readonly ControllerBase _controller; 9 | 10 | public TempDataResultTest(ControllerBase controller) 11 | { 12 | _controller = controller; 13 | } 14 | 15 | public TempDataResultTest AndShouldHaveTempDataProperty(string key, object value = null) 16 | { 17 | _controller.ShouldHaveTempDataProperty(key, value); 18 | return this; 19 | } 20 | 21 | public TempDataResultTest AndShouldHaveTempDataProperty(string key, Func predicate) 22 | { 23 | _controller.ShouldHaveTempDataProperty(key, predicate); 24 | return this; 25 | } 26 | 27 | public TempDataResultTest AndShouldNotHaveTempDataProperty(string empty) 28 | { 29 | _controller.ShouldNotHaveTempDataProperty(empty); 30 | return this; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/TestStack.FluentMVCTesting.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {152CA00F-18D3-4CF5-8CA0-2C5B70CBEA19} 9 | Library 10 | Properties 11 | TestStack.FluentMVCTesting 12 | TestStack.FluentMVCTesting 13 | v4.5 14 | 512 15 | ..\ 16 | 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | false 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | false 39 | 40 | 41 | 42 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 43 | True 44 | 45 | 46 | 47 | 48 | 49 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.Helpers.dll 50 | True 51 | 52 | 53 | ..\packages\Microsoft.AspNet.Mvc.5.2.2\lib\net45\System.Web.Mvc.dll 54 | True 55 | 56 | 57 | ..\packages\Microsoft.AspNet.Razor.3.2.2\lib\net45\System.Web.Razor.dll 58 | True 59 | 60 | 61 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.dll 62 | True 63 | 64 | 65 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Deployment.dll 66 | True 67 | 68 | 69 | ..\packages\Microsoft.AspNet.WebPages.3.2.2\lib\net45\System.Web.WebPages.Razor.dll 70 | True 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 112 | -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/TestStack.FluentMVCTesting.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/TestStack.FluentMVCTesting.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | TestStack.FluentMVCTesting 6 | 7 | 8 | 1.0.0 9 | 10 | 11 | Robert Moore, TestStack 12 | 13 | 14 | Simple, terse, fluent unit testing of ASP.NET MVC Controllers. 15 | ASP.NET MVC 5 version; install FluentMVCTesting.Mvc4 if you are using MVC4 or FluentMVCTesting.Mvc3 if you are using MVC 3. 16 | 17 | 18 | https://github.com/TestStack/TestStack.FluentMVCTesting 19 | 20 | 21 | https://github.com/TestStack/TestStack.FluentMVCTesting/blob/master/LICENSE.txt 22 | 23 | 24 | https://raw.github.com/TestStack/TestStack.FluentMVCTesting/master/logo.png 25 | 26 | 27 | fluent, mvc, asp.net, testing, terse 28 | 29 | 30 | en-US 31 | 32 | 33 | 34 | 35 | 36 | For breaking changes from previous versions see 37 | https://github.com/TestStack/TestStack.FluentMVCTesting/blob/master/BREAKING_CHANGES.md 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/ViewResultTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using System.Text.RegularExpressions; 4 | using System.Web.Helpers; 5 | using System.Web.Mvc; 6 | using ExpressionToString; 7 | 8 | namespace TestStack.FluentMVCTesting 9 | { 10 | public class ViewResultTest 11 | { 12 | private readonly ViewResultBase _viewResult; 13 | private readonly Controller _controller; 14 | 15 | public ViewResultTest(ViewResultBase viewResult, Controller controller) 16 | { 17 | _viewResult = viewResult; 18 | _controller = controller; 19 | } 20 | 21 | public ModelTest WithModel() where TModel : class 22 | { 23 | if (_viewResult.Model == null) 24 | throw new ViewResultModelAssertionException("Expected view model, but was null."); 25 | 26 | var castedModel = _viewResult.Model as TModel; 27 | if (castedModel == null) 28 | throw new ViewResultModelAssertionException(string.Format("Expected view model to be of type '{0}', but it is actually of type '{1}'.", typeof(TModel).Name, _viewResult.Model.GetType().Name)); 29 | 30 | return new ModelTest(_controller); 31 | } 32 | 33 | public ModelTest WithModel(TModel expectedModel) where TModel : class 34 | { 35 | var test = WithModel(); 36 | 37 | var model = _viewResult.Model as TModel; 38 | if (model != expectedModel) 39 | throw new ViewResultModelAssertionException("Expected view model to be the given model, but in fact it was a different model."); 40 | 41 | return test; 42 | } 43 | 44 | public ModelTest WithModel(Expression> predicate) where TModel : class 45 | { 46 | var test = WithModel(); 47 | 48 | var model = _viewResult.Model as TModel; 49 | 50 | var modelLex = Json.Encode(model); 51 | var predicateLex = ExpressionStringBuilder.ToString(predicate); 52 | var compiledPredicate = predicate.Compile(); 53 | 54 | if (!compiledPredicate(model)) 55 | throw new ViewResultModelAssertionException(string.Format( 56 | "Expected view model {0} to pass the given condition ({1}), but it failed.", 57 | modelLex, 58 | predicateLex)); 59 | 60 | return test; 61 | } 62 | 63 | public ModelTest WithModel(Action assertions) where TModel : class 64 | { 65 | var test = WithModel(); 66 | 67 | var model = _viewResult.Model as TModel; 68 | assertions(model); 69 | 70 | return test; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TestStack.FluentMvcTesting/readme.txt: -------------------------------------------------------------------------------- 1 | FluentMVCTesting 2 | ============== 3 | 4 | The main FluentMVCTesting NuGet package has been updated to support .NET 4.5 and MVC5. If you need .NET 4.0 / MVC4 support then use the new FluentMVCTesting.Mvc4 NuGet package. 5 | 6 | * For the project homepage including the current README, see https://github.com/TestStack/TestStack.FluentMVCTesting 7 | * To check for potential breaking changes in this release, see https://github.com/TestStack/TestStack.FluentMVCTesting/blob/master/BREAKING_CHANGES.md 8 | * If you need to raise an issue or check for an existing issue, see https://github.com/TestStack/TestStack.FluentMVCTesting/issues -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TestStack/TestStack.FluentMVCTesting/7e81853353fe858f214ffb4a990bad0784e4ae81/logo.png --------------------------------------------------------------------------------