【问题标题】:ASP.NET MVC, Repository, Unit of work and Entity framework unit testingASP.NET MVC、存储库、工作单元和实体框架单元测试
【发布时间】:2013-11-09 17:22:27
【问题描述】:

我一直在尝试弄清楚如何对我的应用程序进行单元测试,但我不太了解所有内容如何组合在一起。

我遵循了 John Papa 的 PluralSight (SPA) 教程,并以完全相同的方式构建了我的模型、存储库和工作单元。不幸的是,他没有提供任何关于我们如何进行单元测试的示例。

我玩过 Moq 并在网上找到了很少的链接来解释如何做到这一点,但不幸的是我一无所获。

一些提供上下文的代码:

public interface IRepository<T> where T : class
{
    IQueryable<T> GetAll();
    T GetById(int id);
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    void Delete(int id);
}

public interface IFeedbackRepository : IRepository<Feedback>
{
    IQueryable<Feedback> GetByFeedbackFor(int id);
}

public class FeedbackRepository : EFRepository<Feedback>, IFeedbackRepository
{
    public FeedbackRepository(WebAppDbContext context) : base(context) { }
    public IQueryable<Feedback> GetByFeedbackFor(int id) 
    {
        return DbSet.Where(f => f.FeedbackForId == id);
    }
}

public interface IWebAppUow
{
    void Commit();

    IFeedbackRepository Feedbacks { get; }
}

   public void TestMethod1()
    {
     Mock<IWebAppUow> mockUnitOfWork = new Mock<IWebAppUow>();

    // THEN ??
    }

编辑:我找到了这个链接 (http://msdn.microsoft.com/en-us/data/dn314429.aspx),它解释了如何做,但直接在 DbSet 上工作。如果有人可以解释我们如何修改此示例以使用 UoW 和存储库模式,那就太好了!

【问题讨论】:

  • 如果你要测试一些使用它的代码,你需要模拟IWebAppUow。因此,如果没有看到您想要测试的实际代码,就很难回答您的问题。
  • 假设我的 FeedbackRepository 中有以下内容: public Feedback GetByIds(int feedbackForId, int feedbackFromId) { return DbSet.FirstOrDefault( f => f.FeedbackForId == feedbackForId && f.FeedbackFromId == feedbackFromId ); }
  • 那么您可能想要模拟您的存储库。

标签: c# asp.net-mvc entity-framework unit-testing moq


【解决方案1】:

如果您是单元测试新手,测试 EF 并不是最好的开始方式,因为它很难模拟其上下文和所有 API。我建议遵循一些更简单的示例。

对于 EF 单元测试,我建议您查看 Effort frame work。这是它在其网站上的解释

Effort 是一个强大的工具,可以方便地创建 基于实体框架的应用程序的自动化测试。这是 基本上是一个执行所有数据操作的 ADO.NET 提供程序 一个轻量级的进程内主内存数据库,而不是传统的 外部数据库。它也提供了一些直观的帮助方法 使用现有的 ObjectContext 或 DbContext 类。对现有代码的简单添加可能就足够了 创建可以在不存在的情况下运行的数据驱动测试 外部数据库。

【讨论】:

  • 我之前做过很多单元测试,但一般没有在 ASP.NET 或 WebApplicatios 上进行过......
【解决方案2】:

我不会对您的存储库进行单元测试,DbContext 是一个依赖于真实数据库的具体类,据我所知,我无法用 Moq 模拟它。所以我所做的就是专注于对使用存储库的代码进行单元测试并模拟存储库。

要实际测试您的存储库,我会进行集成测试。

【讨论】:

  • 使用存储库的代码将是控制器使用的 Uow。您是否建议改为进行单元测试?
  • 我不确定那个架构。我熟悉的架构是服务将依赖于 UoW 和存储库,您可以模拟这两者并对服务方法进行单元测试。
  • 我遵循了 John Papa 在 hia SPA 复数教程中使用的架构。你有给正在讨论的人的教程吗?我必须承认我从来没有进入过我的架构,我通常尽可能地保持它的简单,但是在这个项目中,我试图从一开始就让它正确。可维护、可扩展且易于新手加入。
  • @teh0wner,看看这个洋葱架构的例子:github.com/shawnmclean/OnionArchitecture
  • 刚刚经历了那个解决方案,我很高兴你向我提出了建议!关注点的分离非常清晰,松散耦合,但我想知道一件事; OnionArchitecure.Infrastructure 有 2 个空文件夹。那里通常会放什么?
【解决方案3】:

所以,如果我正确理解了您的评论,您想测试 FeedbackRepository 类的方法。 让我们看看GetByFeedbackFor方法是怎么做的。

您在FeedbackRepository 中传递了WebAppDbContext context。这不是很好。可能您将无法测试此代码。您应该提取IWebAppDbContext 接口并将其传递给FeedbackRepository ctor。

我不知道这段代码的背后是什么 return DbSet.Where(f =&gt; f.FeedbackForId == id); 所以我只能猜测这是基类的一些属性...但是如果假设您在这里使用上下文而不是DbSet 属性,那么您的测试方法将如下所示(我认为重写它不会太难基本属性的情况(或者甚至可以按原样工作)):

public void ShouldReturnFeedbacksForCorrectId()
{
  var contextMock = new Mock<IWebAppDbContext>();

  // fill expected for example with 2 entities with FeedbackForId == 1
  IQueryable<Feedback> expected = InitWithDataSomehow();
  contextMock.Setup(i => i.Feedbacks).Returns(expected);
  var repositoryUnderTest = new FeedbackRepository(contextMock);

  IQueryable<Feedback> actualResult = repositoryUnderTest.GetByFeedbackFor(1);

  Assert.AreEqual(expected, actualResult);
}

【讨论】:

  • 你理解的没错。我会将 WebAppDbContext 提取到一个接口中,看看它是否有效!我会尽快回复您。
  • 我的 WebAppDbContext 扩展了在 ASP.NET Identity 中使用的 IdentityContext。我将如何继续这样做?
猜你喜欢
  • 1970-01-01
  • 2012-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-17
  • 2017-03-25
  • 2012-12-27
相关资源
最近更新 更多