【问题标题】:ASP.NET MVC, RavenDb and Unit TestingASP.NET MVC、RavenDb 和单元测试
【发布时间】:2012-05-12 09:31:18
【问题描述】:

我刚刚开始使用 RavenDB,到目前为止我很喜欢它。然而,我坚持如何对与之交互的控制器操作进行单元测试。

我发现的所有问题/文章都像这样:Unit testing RavenDb queries 告诉我应该在内存中使用 RavenDB 而不是模拟它,但我找不到一个可靠的例子来说明如何做到这一点。

例如,我有一个控制器操作来将员工添加到数据库(是的,它过于简化了,但我不想让问题复杂化)

public class EmployeesController : Controller
{

  IDocumentStore _documentStore;
  private IDocumentSession _session;

  public EmployeesController(IDocumentStore documentStore)
  {
    this._documentStore = documentStore;

  }

  protected override void OnActionExecuting(ActionExecutingContext filterContext)
  {
    _session = _documentStore.OpenSession("StaffDirectory");
  }

  protected override void OnActionExecuted(ActionExecutedContext filterContext)
  {
      if (_session != null && filterContext.Exception == null) {
        _session.SaveChanges();
        _session.Dispose();
    }
  }

  [HttpGet]
  public ViewResult Create()
  {
    return View();
  }

  [HttpPost]
  public RedirectToRouteResult Create(Employee emp)
  {
    ValidateModel(emp);
    _session.Store(emp);
    return RedirectToAction("Index");
  }

如何验证在单元测试中添加到数据库的内容?有没有人有任何在 MVC 应用程序中涉及 RavenDb 的单元测试示例?

如果这很重要,我正在使用 MSTest,但我很乐意尝试翻译来自其他框架的测试。

谢谢。

编辑

好的,我的测试初始化​​创建了注入到控制器构造函数中的文档存储,但是当我运行我的测试时,OnActionExecuting 事件没有运行,因此没有要使用的会话,并且测试失败并出现空引用异常。

[TestClass]
public class EmployeesControllerTests
{
  IDocumentStore _store;

  [TestInitialize]
  public void InitialiseTest()
  {
    _store = new EmbeddableDocumentStore
    {
      RunInMemory = true
    };
    _store.Initialize();
  }

  [TestMethod]
  public void CreateInsertsANewEmployeeIntoTheDocumentStore()
  {
    Employee newEmp = new Employee() { FirstName = "Test", Surname = "User" };

    var target = new EmployeesController(_store);
    ControllerUtilities.SetUpControllerContext(target, "testUser", "Test User", null);

    RedirectToRouteResult actual = target.Create(newEmp);
    Assert.AreEqual("Index", actual.RouteName);

    // verify employee was successfully added to the database.
  }
}

我错过了什么?如何获取创建的会话以在测试中使用?

【问题讨论】:

  • 我已经更新了我的问题,见下文

标签: c# asp.net-mvc unit-testing mstest ravendb


【解决方案1】:

运行单元测试后,只需断言数据库中有一个新文档并且它设置了正确的字段。

var newDoc = session.Load<T>(docId)

var docs = session.Query<T>.Where(....).ToList();

存在 RavenDB 内存模式,因此您不必模拟它,您只需执行以下操作:

  • 打开一个新的内存嵌入式文档存储(没有数据)
  • 如果需要,插入单元测试运行所需的任何数据
  • 运行单元测试
  • 查看内存存储中的数据,看看它是否已正确更新

更新如果您想要完整的示例,请查看 RacoonBlog 代码是如何实现的,这是运行 Ayende's blog 的代码。查看这两个文件:

【讨论】:

  • 是的,我一直在寻找一个更完整的例子,因为我已经做到了 :) 请参阅我的问题以获取更多信息。
【解决方案2】:

如何验证在单元测试中添加到数据库的内容?

你没有。我们不在单元测试中测试这些东西。这是集成测试的责任,而不是单元测试。

如果您想对依赖于某些外部源(如您的数据库)的类进行单元测试,请模拟数据库访问。

编辑:

为了纠正一些提到的错误,我将引用 MSDN 的定义(但所有其他资源都同意):

单元测试的主要目标是取最小的一块 应用程序中的可测试软件,将其与其余部分隔离 代码,并确定其行为是否完全符合您的预期。

如果不进行模拟,您将忽略单元测试的基本原则 - 隔离和测试尽可能小的部分。单元测试需要持久无知,并且不应该依赖于某些外部类。如果数据库随时间变化怎么办?重写所有测试,即使功能完全一样?

来吧。你可以给我 -1 你想要多少次,但这不会让你正确。

【讨论】:

  • 没错,但 RavenDB 的内存模式让集成测试变得如此简单,您通常无需费心进行单元测试和模拟所有内容
  • @MattWarren,嗯,我认为我们编写测试是为了持久无知......这不是关于它是否容易的问题。单元测试不应该超出类边界,否则它将是一个集成测试。无论您的数据库是在内存中、文件中还是在完全不同的服务器上,都没有关系。恐怕原理保持不变......
  • 通常使用像 SQL Server 这样的 RDBMS,我会有一个存储库并为这些测试模拟它。然而,我在 RavenDB 上读过的所有文章,包括 Ayende 的博客,都说不要那样做......所以我想我会尝试一下。
  • @Nick,不同之处在于,通过模拟,您实际使用什么数据库并不重要。通过使用实际存储,您将自己限制在您设置的一个特定数据库中。如果您更改数据库,您几乎可以重写所有测试,因为它们将 1000% 失败。单元测试不应依赖于某些特定外部存储的使用。这样做违反了基本原则。你真正需要的是集成测试。它还能工作吗?当然。这是推荐的方法吗?我不这么认为。不过你的电话。只是想指出单元测试的主要思想......
  • @Walther,我很欣赏所涉及的原则,并经常给我的团队留下深刻印象,因为我认为他们会倾听 :) 但这次我想更加务实一点,而不是担心这种关系使用 RavenDB。老实说,虽然我通常尽可能地坚持原则,但在超过 15 年的专业发展中,我认为我从来没有在开始一个项目后更换过应用程序上的数据存储。 :\但是是的,我理解你的担忧。
【解决方案3】:

由于您提到的链接到的线程通过嵌入 RavenDB 来使用 EmbeddableDocumentStore。

设置方法如下: http://msdn.microsoft.com/en-us/magazine/hh547101.aspx

以下是如何在 raven 中使用存储库模式,以便您轻松测试: http://novuscraft.com/blog/ravendb-and-the-repository-pattern

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-01
    相关资源
    最近更新 更多