如何为使用 RenderPartialViewToString 返回 JsonResult 的方法编写单元测试?

发布于 2024-09-13 22:06:26 字数 425 浏览 10 评论 0原文

如果您查看此链接中的示例:

http://www.atlanticbt.com/blog/asp-net-mvc-using-ajax-json-and-partialviews/

如何为 JsonAdd 方法编写单元测试?我自己的代码中也有类似的情况,但是调用时出现 RenderPartialViewToString 错误:

ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView

我尝试了不同的方法来尝试存根该调用,但无济于事。任何帮助表示赞赏。谢谢。

If you look at the example at this link:

http://www.atlanticbt.com/blog/asp-net-mvc-using-ajax-json-and-partialviews/

How would one write a unit test for the JsonAdd method? I have a similar situation in my own code, but the RenderPartialViewToString errors when calling:

ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView

I've tried different ways of trying to stub that call to no avail. Any help appreciated. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

囍孤女 2024-09-20 22:06:26

我在使用 RenderPartialViewToString 进行单元测试时遇到了很多麻烦。
我通过做两件事成功了。
我必须模拟视图引擎和控制器上下文。

这是代码:

public ViewEngineResult SetupViewContent(string viewName, string viewHtmlContent)
    {
        var mockedViewEngine = new Mock<IViewEngine>();
        var resultView = new Mock<IView>();

        resultView.Setup(x => x.Render(It.IsAny<ViewContext>(), It.IsAny<TextWriter>()))
            .Callback<ViewContext, TextWriter>((v, t) =>
            {
                t.Write(viewHtmlContent);
            });

        var viewEngineResult = new ViewEngineResult(resultView.Object, mockedViewEngine.Object);
        mockedViewEngine.Setup(x => x.FindPartialView(It.IsAny<ControllerContext>(), viewName, It.IsAny<bool>()))
            .Returns<ControllerContext, string, bool>((controller, view, useCache) =>
            {
                return viewEngineResult;
            });

        mockedViewEngine.Setup(x => x.FindView(It.IsAny<ControllerContext>(), viewName, It.IsAny<string>(), It.IsAny<bool>()))
            .Returns<ControllerContext, string, string, bool>((controller, view, masterName, useCache) =>
            {
                return viewEngineResult;
            });

        ViewEngines.Engines.Clear();
        ViewEngines.Engines.Add(mockedViewEngine.Object);
        return viewEngineResult;
    }

    public void SetContext(ref PointCollecteLivraisonController controller)
    {
        SetupViewContent("MyViewName", "TheViewContent");

        var httpContextBase = new Mock<HttpContextBase>();
        var httpRequestBase = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var routes = new RouteCollection();
        RouteConfigurator.RegisterRoutes(routes);
        var routeData = new RouteData();
        routeData.Values.Add("controller", "PointCollecteLivraison");
        routeData.Values.Add("action", "RechercheJson");

        httpContextBase.Setup(x => x.Response).Returns(response.Object);
        httpContextBase.Setup(x => x.Request).Returns(httpRequestBase.Object);
        httpContextBase.Setup(x => x.Session).Returns(session.Object);
        session.Setup(x => x["somesessionkey"]).Returns("value");
        httpRequestBase.Setup(x => x.Form).Returns(new NameValueCollection());
        controller.ControllerContext = new ControllerContext(httpContextBase.Object, routeData, controller);
        controller.Url = new UrlHelper(new RequestContext(controller.HttpContext, routeData), routes);
    }

这就是我使用它的方式:

PointCollecteLivraisonController controller = new PointCollecteLivraisonController();
SetContext(ref controller);

这是我的来源:
查看引擎模拟:http://thoai- nguyen.blogspot.fr/2011/04/test-mock-mvc-view-engine.html

控制器上下文模拟:ASP.NET MVC - 使用 Moq 框架对 RenderPartialViewToString() 进行单元测试?

希望有所帮助。

I had a lot of trouble to make unit test working with RenderPartialViewToString.
I succeeded by doing 2 things.
I had to mock the view engine and the controller context.

Here the code :

public ViewEngineResult SetupViewContent(string viewName, string viewHtmlContent)
    {
        var mockedViewEngine = new Mock<IViewEngine>();
        var resultView = new Mock<IView>();

        resultView.Setup(x => x.Render(It.IsAny<ViewContext>(), It.IsAny<TextWriter>()))
            .Callback<ViewContext, TextWriter>((v, t) =>
            {
                t.Write(viewHtmlContent);
            });

        var viewEngineResult = new ViewEngineResult(resultView.Object, mockedViewEngine.Object);
        mockedViewEngine.Setup(x => x.FindPartialView(It.IsAny<ControllerContext>(), viewName, It.IsAny<bool>()))
            .Returns<ControllerContext, string, bool>((controller, view, useCache) =>
            {
                return viewEngineResult;
            });

        mockedViewEngine.Setup(x => x.FindView(It.IsAny<ControllerContext>(), viewName, It.IsAny<string>(), It.IsAny<bool>()))
            .Returns<ControllerContext, string, string, bool>((controller, view, masterName, useCache) =>
            {
                return viewEngineResult;
            });

        ViewEngines.Engines.Clear();
        ViewEngines.Engines.Add(mockedViewEngine.Object);
        return viewEngineResult;
    }

    public void SetContext(ref PointCollecteLivraisonController controller)
    {
        SetupViewContent("MyViewName", "TheViewContent");

        var httpContextBase = new Mock<HttpContextBase>();
        var httpRequestBase = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var routes = new RouteCollection();
        RouteConfigurator.RegisterRoutes(routes);
        var routeData = new RouteData();
        routeData.Values.Add("controller", "PointCollecteLivraison");
        routeData.Values.Add("action", "RechercheJson");

        httpContextBase.Setup(x => x.Response).Returns(response.Object);
        httpContextBase.Setup(x => x.Request).Returns(httpRequestBase.Object);
        httpContextBase.Setup(x => x.Session).Returns(session.Object);
        session.Setup(x => x["somesessionkey"]).Returns("value");
        httpRequestBase.Setup(x => x.Form).Returns(new NameValueCollection());
        controller.ControllerContext = new ControllerContext(httpContextBase.Object, routeData, controller);
        controller.Url = new UrlHelper(new RequestContext(controller.HttpContext, routeData), routes);
    }

And that is the way i use it all :

PointCollecteLivraisonController controller = new PointCollecteLivraisonController();
SetContext(ref controller);

Here are my sources :
View engine mocking : http://thoai-nguyen.blogspot.fr/2011/04/test-mock-mvc-view-engine.html

Controller context mocking : ASP.NET MVC - Unit testing RenderPartialViewToString() with Moq framework?

Hope this help.

软糯酥胸 2024-09-20 22:06:26

由于 ViewEninges 是一个静态类,因此您无法使用 RhinoMocks 来模拟它。我认为你最好的选择是创建一个“部分视图渲染器”界面。界面是可模拟的,因此您将能够消除渲染视图的复杂性。这是一些快速的伪代码。

首先,定义部分视图渲染器接口:

public interface IRenderPartialView
{
    string Render(string viewName, object model);
}

然后,将基类的 RenderPartialViewToString 更改为 IRenderPartialView.Render 的实现:

public abstract class BaseController : Controller, IRenderPartialView
{
...
    public string Render(string viewName, object model)
    {
        // same code as RenderPartialViewToString
    }
}

现在我们需要更改控制器构造函数,以便我们可以在测试期间注入 IRenderPartialView - 但使用基类一在生产过程中。我们可以通过使用一对构造函数来完成此操作:

public class YourController : BaseController
{
        private IRenderPartialView partialRenderer;

        public YourController()
        {
            SetRenderer(this);
        }

        public YourController(IRenderPartialView partialRenderer)
        {
            SetRenderer(partialRenderer);
        }

        private void SetRenderer(IRenderPartialView partialRenderer)
        {
            this.partialRenderer = this;
        }
}

现在,JsonAdd 可以调用部分视图渲染器:

public JsonResult JsonAdd(AddPersonViewModel AddPersonModel)
{
    ...
    return Json(new
    {
        Success = true,
        Message = "The person has been added!",
        PartialViewHtml = partialRenderer.Render("PersonList", new PersonListViewModel {PersonList = _personList})
    });
}

因此,在测试期间,您将模拟一个 IRenderPartialView 并将其发送到接受 IRenderPartialView 的构造函数代码>IRenderPartialView。在生产过程中,当 ASP.NET MVC 调用默认构造函数时,它将使用控制器作为渲染器(在基类中具有 IRenderPartialView.Render 的实现)。

Since ViewEninges is a static class, you can't mock it with RhinoMocks. I think your best bet is to create a "partial view renderer" interface. An interface is mockable so you'll be able to stub out the complexity of rendering the view. Here's some quick pseudo-code thrown together.

First, define the partial view renderer interface:

public interface IRenderPartialView
{
    string Render(string viewName, object model);
}

Then, change your base class' RenderPartialViewToString to be the implementation of IRenderPartialView.Render:

public abstract class BaseController : Controller, IRenderPartialView
{
...
    public string Render(string viewName, object model)
    {
        // same code as RenderPartialViewToString
    }
}

Now we need to change your controller constructors so we can inject an IRenderPartialView during testing -- but use the base class one during production. We can accomplish this by using a pair of constructors:

public class YourController : BaseController
{
        private IRenderPartialView partialRenderer;

        public YourController()
        {
            SetRenderer(this);
        }

        public YourController(IRenderPartialView partialRenderer)
        {
            SetRenderer(partialRenderer);
        }

        private void SetRenderer(IRenderPartialView partialRenderer)
        {
            this.partialRenderer = this;
        }
}

Now, JsonAdd can call the partial view renderer:

public JsonResult JsonAdd(AddPersonViewModel AddPersonModel)
{
    ...
    return Json(new
    {
        Success = true,
        Message = "The person has been added!",
        PartialViewHtml = partialRenderer.Render("PersonList", new PersonListViewModel {PersonList = _personList})
    });
}

So, during testing, you'll mock out an IRenderPartialView and send that to the constructor that accepts an IRenderPartialView. During production, when ASP.NET MVC calls your default constructor, it will use the controller as the renderer (which has the implementation of IRenderPartialView.Render inside the base class).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文