【问题标题】:Mocking DbContext for TDD Repository模拟 TDD 存储库的 DbContext
【发布时间】:2015-01-23 17:08:00
【问题描述】:

试图模拟与我的存储库耦合的我的 EF 上下文。 我正在使用 Moq,试图设置一个模拟的上下文并通过构造函数将其传递到存储库中。

之后我调用 Add 方法,简单地添加一个新对象,然后我尝试通过检查我传入的上下文是否已更改状态来断言...

我得到的错误是 NullReference 异常,我猜是因为我的模拟不正确..

这是代码:

使用不工作的模拟进行测试

[TestClass]
public class GameRepositoryTests
{
    [TestMethod]
    public void PlayerThatWonMustBeAddedToTopList()
    {
        // Arrange
        var expected = "Player added successfully";

        var dbContextMock = new Mock<Context>();
        // Need to setup the Context??

        IRepository gameRepository = new GameRepository(dbContextMock.Object);

        var user = "MyName";

        // Act
        gameRepository.Add(user);

        // Assert

        dbContextMock.VerifySet(o => o.Entry(new ScoreBoard()).State = EntityState.Added);
    }
}

public class ScoreBoard
{

}

存储库

public class GameRepository : IRepository
{
    private readonly Context _context;

    public GameRepository()
        : this(new Context())
    {
        // Blank!
    }

    // Passing in the Mock here...
    public GameRepository(Context context)
    {
        this._context = context;
    }

    // Method under test...
    public void Add<T>(T entity) where T : class
    {
        _context.Set<T>().Add(entity);
    }
}

上下文

public class Context : DbContext
{
    public Context()
        : base("name=DefaultConnection")
    {

    }
}

【问题讨论】:

  • 哪一行抛出异常? null 是哪个对象?该对象在哪里设置?我会猜测.Set&lt;T&gt;() 正在返回null。模拟可能需要在安排步骤中被告知要从中返回什么。
  • _context.Set().Add(entity);
  • 这也是使用 Entity Framework 的存储库是个坏主意的另一个原因。您实际上是在测试您的 repo 的 Add 方法是否调用了 DbSetAdd 方法。那里有一些开创性的东西。
  • @ChrisPratt 我很难弄清楚。我只是想学习 TDD 并遵循严格的红色、绿色、重构模式......所以,如果我想要这段代码,基本上这就是我必须做的吗?总体而言,.NET 似乎很难 TDD:ing,它有很多嘲弄,而且您似乎必须是专家:/ 您能给我指出一个更简单的方向吗?
  • 嗯,是的,当然,但我的意思是测试本身应该是指导性的。当您编写测试时,重点是确保您在想要添加某些内容时正确调用Add,而不是我不知道Delete,这应该告诉您您的代码正在增加复杂性,而不是删除它。

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


【解决方案1】:

您需要模拟出Set&lt;T&gt;() 调用。

这样的事情应该可以解决。

// Arrange
var context = new Mock<Context>();
var set = new Mock<DbSet<User>>();

context.Setup(c => c.Set<User>()).Returns(set.Object);

// Act

// Assert
set.Verify(s => s.Add(It.IsAny<User>()), Times.Once());

除了在底层DbSet 上调用了Add() 之外,您实际上不需要验证任何内容。对实体状态已修改的事实进行验证是不必要的。如果您确认调用了 Add() 就足够了,因为您可以放心地假设 EF 工作正常。

此示例仅适用于您的用户对象的存储库。您必须为要以这种方式测试的每个存储库设置不同的模拟。如果需要,您可能可以编写一个更通用的版本。

【讨论】:

  • 谢谢伙计!我会直接试试这个,稍后再回复!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-14
  • 1970-01-01
  • 2012-02-23
  • 1970-01-01
  • 1970-01-01
  • 2020-09-09
  • 2017-07-16
相关资源
最近更新 更多