|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
namespace Microsoft.AspNetCore.Mvc;
// These tests cover the logic included in ViewResult.ExecuteResultAsync - see ViewResultExecutorTest
// and ViewExecutorTest for more comprehensive tests.
public class ViewResultTest
{
[Fact]
public void Model_NullWhenViewDataIsNull()
{
// Arrange
var viewResult = new ViewResult();
// Act & Assert
Assert.Null(viewResult.Model);
}
[Fact]
public void Model_ExposesViewDataModel()
{
// Arrange
var customModel = new object();
var viewResult = new ViewResult
{
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider())
{
Model = customModel
},
};
// Act & Assert
Assert.Same(customModel, viewResult.Model);
}
[Fact]
public async Task ExecuteResultAsync_Throws_IfServicesNotRegistered()
{
// Arrange
var actionContext = new ActionContext(new DefaultHttpContext() { RequestServices = Mock.Of<IServiceProvider>(), }, new RouteData(), new ActionDescriptor());
var expected =
$"Unable to find the required services. Please add all the required services by calling " +
$"'IServiceCollection.AddControllersWithViews()' inside the call to 'ConfigureServices(...)' " +
$"in the application startup code.";
var viewResult = new ViewResult();
// Act
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => viewResult.ExecuteResultAsync(actionContext));
// Assert
Assert.Equal(expected, ex.Message);
}
[Fact]
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesGetViewLocations()
{
// Arrange
var viewName = "MyView";
var actionContext = GetActionContext();
var expected = string.Join(
Environment.NewLine,
$"The view '{viewName}' was not found. The following locations were searched:",
"Location1",
"Location2");
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, viewName, /*isMainPage*/ true))
.Returns(ViewEngineResult.NotFound(viewName, Enumerable.Empty<string>()))
.Verifiable();
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), viewName, /*isMainPage*/ true))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "Location1", "Location2" }))
.Verifiable();
var viewResult = new ViewResult
{
ViewEngine = viewEngine.Object,
ViewName = viewName,
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
TempData = Mock.Of<ITempDataDictionary>(),
};
// Act and Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => viewResult.ExecuteResultAsync(actionContext));
Assert.Equal(expected, ex.Message);
viewEngine.Verify();
}
[Fact]
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesFindViewLocations()
{
// Arrange
var viewName = "MyView";
var actionContext = GetActionContext();
var expected = string.Join(
Environment.NewLine,
$"The view '{viewName}' was not found. The following locations were searched:",
"Location1",
"Location2",
"Location3",
"Location4");
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, viewName, /*isMainPage*/ true))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "Location1", "Location2" }))
.Verifiable();
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), viewName, /*isMainPage*/ true))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "Location3", "Location4" }))
.Verifiable();
var viewResult = new ViewResult
{
ViewEngine = viewEngine.Object,
ViewName = viewName,
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
TempData = Mock.Of<ITempDataDictionary>(),
};
// Act and Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => viewResult.ExecuteResultAsync(actionContext));
Assert.Equal(expected, ex.Message);
viewEngine.Verify();
}
[Fact]
public async Task ExecuteResultAsync_Throws_IfViewCouldNotBeFound_MessageUsesAllLocations()
{
// Arrange
var viewName = "MyView";
var actionContext = GetActionContext();
var expected = string.Join(
Environment.NewLine,
$"The view '{viewName}' was not found. The following locations were searched:",
"Location1",
"Location2",
"Location3",
"Location4");
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, viewName, /*isMainPage*/ true))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "Location1", "Location2" }))
.Verifiable();
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), viewName, /*isMainPage*/ true))
.Returns(ViewEngineResult.NotFound(viewName, new[] { "Location3", "Location4" }))
.Verifiable();
var viewResult = new ViewResult
{
ViewEngine = viewEngine.Object,
ViewName = viewName,
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
TempData = Mock.Of<ITempDataDictionary>(),
};
// Act and Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => viewResult.ExecuteResultAsync(actionContext));
Assert.Equal(expected, ex.Message);
viewEngine.Verify();
}
[Fact]
public async Task ExecuteResultAsync_FindsAndExecutesView()
{
// Arrange
var viewName = "MyView";
var actionContext = GetActionContext();
var view = new Mock<IView>(MockBehavior.Strict);
view
.Setup(v => v.RenderAsync(It.IsAny<ViewContext>()))
.Returns(Task.FromResult(0))
.Verifiable();
view
.As<IDisposable>()
.Setup(v => v.Dispose())
.Verifiable();
// Used by logging
view
.SetupGet(v => v.Path)
.Returns($"{viewName}.cshtml");
var viewEngine = new Mock<IViewEngine>(MockBehavior.Strict);
viewEngine
.Setup(v => v.GetView(/*executingFilePath*/ null, viewName, /*isMainPage*/ true))
.Returns(ViewEngineResult.NotFound(viewName, Enumerable.Empty<string>()))
.Verifiable();
viewEngine
.Setup(v => v.FindView(It.IsAny<ActionContext>(), viewName, /*isMainPage*/ true))
.Returns(ViewEngineResult.Found(viewName, view.Object))
.Verifiable();
var viewResult = new ViewResult
{
ViewName = viewName,
ViewEngine = viewEngine.Object,
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
TempData = Mock.Of<ITempDataDictionary>(),
};
// Act
await viewResult.ExecuteResultAsync(actionContext);
// Assert
view.Verify();
viewEngine.Verify();
}
private ActionContext GetActionContext()
{
return new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor());
}
private HttpContext GetHttpContext()
{
var options = Options.Create(new MvcViewOptions());
var viewExecutor = new ViewResultExecutor(
options,
new TestHttpResponseStreamWriterFactory(),
new CompositeViewEngine(options),
Mock.Of<ITempDataDictionaryFactory>(),
new DiagnosticListener("Microsoft.AspNetCore"),
NullLoggerFactory.Instance,
new EmptyModelMetadataProvider());
var services = new ServiceCollection();
services.AddSingleton<IActionResultExecutor<ViewResult>>(viewExecutor);
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = services.BuildServiceProvider();
return httpContext;
}
}
|