【问题标题】:Integration Testing ASP.NET MVC Applications集成测试 ASP.NET MVC 应用程序
【发布时间】:2016-11-08 17:44:21
【问题描述】:

我以前从未测试过 ASP.NET MVC3 应用程序,尽管我在 NUnit/JUnit/等方面拥有丰富的经验。和TDD。我的问题是,我可以使用什么样的策略来测试 MVC 应用程序?

编辑:我在这里主要关注测试策略,同时也关注集成测试——测试真正的用户在点击我的应用程序时会经历什么。

我的设置是 ASP.NET MVC 和 ORM(NHibernate 或 Dapper,取决于项目)。

是否有类似于 NUnit 的基于 Web 的测试套件?我应该写一个吗?还是我应该(以某种方式)尝试将我的应用程序分解为一百万个小的非 Web DLL 并在 NUnit 中测试它们? (使用 ActiveRecord/NHibernate 作为 ORM 层是否可能?)

您如何测试这种应用程序?

我查看了类似的 SO 问题,除了“这里是如何测试控制器”之外,没有发现太多。

【问题讨论】:

  • mvc 从一开始就为方便测试而构建,它允许您独立测试控制器方法、视图和模型,您正在寻找什么样的类似于 NUnit 的套件?为什么不只使用 NUnit ?你也可以使用 R#,它可以让你轻松运行 NUnit 测试

标签: asp.net-mvc testing


【解决方案1】:

有不同类型的测试:单元、集成、验收,...

如果您谈论的是单元测试,那么 ASP.NET MVC 在构建时就考虑到了可测试性。有许多文章说明了这些概念。这是one example。和another one。然而another one。如果您希望您的应用程序是可单元测试的,您必须以这样一种方式设计它,即不同层之间存在弱耦合。因此,例如,您将抽象控制器将使用的接口后面的所有数据访问。您将使用一个 DI 框架,它将一个具体的实现(NHibernate 或其他)传递给控制器​​,在单元测试中,您将能够使用一个模拟框架来存根数据访问层并完全隔离地测试这个控制器。

【讨论】:

  • +1 这看起来像我要找的东西。 Rails 有这个工具,您可以在其中说“转到此 URL,单击此链接,检查 HTML 是否包含 blah blah blah。”这在 MVC3 中可能吗? (我还没有详细查看您的链接)
  • @ashes999,如果你有 Visual Studio 的测试版或终极版,你可以使用内置的 Web and Load Tests。如果没有,您可以查看WatiN
【解决方案2】:

当我们谈论 ASP.NET MVC 应用程序的集成测试时,有两点需要考虑:

  1. 测试套件应该像用户使用 Web 浏览器那样与应用程序交互
  2. 测试套件应该能够在测试会话期间隔离(模拟)Web 应用程序的不同部分。

如果这是你的情况,那么这是我的食谱:

  1. 通过命令行使用 IIS Express 托管您的 Web 应用程序

    iisexpress.exe /path:[path] /port:[port] 
    
  2. 使用Selenium web driver 模拟浏览器活动。

  3. 使用SpecFlowgherkin 语言定义用户会话
  4. 使用Deleporter 在运行时模拟 Web 应用程序组件

我已经写了详细的article 关于这种方法。 还有一个github repo 实现了这种方法。

【讨论】:

  • 路径应该指向WebApplication.csproj文件所在的目录吗?不是bin
  • @ath 路径应该指向包含所有资产、配置文件和配置文件的 Web 应用程序根目录
【解决方案3】:

如果您已经熟悉 Nunit / Junit 和 TDD,只需将这些策略应用于 MVC Web 应用程序的单元测试。

无需编写基于 Web 的测试套件,也无需将您的应用程序分解为“数百万”个小非 Web dll。话虽如此,您仍然需要将应用程序设计为可测试的。

一个非常简单的控制器测试可能如下所示。请注意,我的示例将 Moq 用于存储库/DI。

[Test]
public void Edit_Get_Should_Lookup_Contact_From_Repository_And_Return_Edit_View()
{
    // arrange
    var _repository = new Mock<IContactRepository>();

    var expectedContact = new Contact
    {
        First = "first",
        Last = "last",
        Email = "mail@test.com"
    };

    var mockContext = new Mock<ControllerContext>();
    _repository.Setup(x => x.GetById(It.IsAny<int>())).Returns(expectedContact);

    var controller = new ContactController(_repository.Object)
    {
        ControllerContext = mockContext.Object
    };

    // act
    var result = controller.Edit(1) as ViewResult;
    var resultData = (Contact)result.ViewData.Model;

    // assert
    Assert.AreEqual("Edit", result.ViewName);
    Assert.AreEqual(expectedContact.First, resultData.First);
    Assert.AreEqual(expectedContact.Last, resultData.Last);
    Assert.AreEqual(expectedContact.Email, resultData.Email);
}

[HttpGet]
public ActionResult Edit(int id)
{
    var contact = _repository.GetById(id);

    return View("Edit", contact);
}

如果您想要更多单元测试/mvc 示例,请浏览 nerd Dinner 示例应用程序:http://nerddinner.codeplex.com/

【讨论】:

  • 这个答案涉及单元测试。我的意思是更多的集成测试(例如登录,浏览到页面 X,点击 Y,...)
  • @ashes999,我已经成功地将 Watin 用于您刚才提到的测试类型:watin.org
  • 是的,达林也是这么建议的。
【解决方案4】:

我认为这取决于您要测试的内容。如果您想从 UI 进行测试,您需要使用某种 UI 驱动程序,例如 SeleniumWatin

如果您还将Specflow 与这些网络驱动程序之一一起使用,您可以像在 ruby​​ 中那样编写规范。

我自己不会通过 UI 进行测试,因为我认为 UI 会发生很大变化。我会通过 MVC 应用程序中的控制器来集中推动接受度,并保持控制器非常小,其中包含最少的逻辑。我认为控制器应该只提供输入的一些基本验证,而不是委托给您的应用程序。

所有这一切还取决于您的应用程序有多复杂,主要的经验法则应该是保持简单:)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多