使用Mock IDbSet进行Entity Framework的单元测试

10

我之前从来没有进行过单元测试,而且在我的第一个测试中遇到了问题。问题是_repository.Golfers.Count();总是显示DbSet为空。

我的测试很简单,我只是尝试添加一个新的高尔夫球手。

[TestClass]
public class GolferUnitTest //: GolferTestBase
{
    public MockGolfEntities _repository;

    [TestMethod]
    public void ShouldAddNewGolferToRepository()
    {
        _repository = new MockGolfEntities();

        _repository.Golfers = new InMemoryDbSet<Golfer>(CreateFakeGolfers());

        int count = _repository.Golfers.Count();
        _repository.Golfers.Add(_newGolfer);

        Assert.IsTrue(_repository.Golfers.Count() == count + 1);
    }

    private Golfer _newGolfer = new Golfer()
    {
        Index = 8,
        Guid = System.Guid.NewGuid(),
        FirstName = "Jonas",
        LastName = "Persson"
    };
    public static IEnumerable<Golfer> CreateFakeGolfers()
    {
        yield return new Golfer()
        {
            Index = 1,
            FirstName = "Bill",
            LastName = "Clinton",
            Guid = System.Guid.NewGuid()
        };
        yield return new Golfer()
        {
            Index = 2,
            FirstName = "Lee",
            LastName = "Westwood",
            Guid = System.Guid.NewGuid()
        };
        yield return new Golfer()
        {
            Index = 3,
            FirstName = "Justin",
            LastName = "Rose",
            Guid = System.Guid.NewGuid()
        };
    }

我使用Entity Framework和Code First构建了一个数据模型。为了测试我的上下文,我模拟了IDbSet的派生类(感谢那些我无法准确记忆的在线人员)。

public class InMemoryDbSet<T> : IDbSet<T> where T : class
{
    readonly HashSet<T> _set;
    readonly IQueryable<T> _queryableSet;

    public InMemoryDbSet() : this(Enumerable.Empty<T>()) { }

    public InMemoryDbSet(IEnumerable<T> entities)
    {
        _set = new HashSet<T>();

        foreach (var entity in entities)
        {
            _set.Add(entity);
        }

        _queryableSet = _set.AsQueryable();
    }

    public T Add(T entity)
    {
        _set.Add(entity);
        return entity;

    }

    public int Count(T entity)
    {
        return _set.Count();
    }

    // bunch of other methods that I don't want to burden you with
}

当我进行调试并逐步执行代码时,我可以看到我实例化了_repository并用三个伪高尔夫球手填充它,但当我退出添加函数时,_respoistory.Golfers又变为空了。当我添加新的高尔夫球员时,_set.Add(entity)运行并添加了高尔夫球员,但是再次_respoistory.Golfers为空。我错过了什么?
更新
对不起我是个白痴,但我没有在我的MockGolfEntities上实现set。原因是我之前尝试过但无法弄清楚如何移动,然后忘记了它。那么,我该如何设置IDbSet?这是我尝试过的,但它给了我一个堆栈溢出错误。我感觉像个白痴,但我想不出如何编写设置函数。
public class MockGolfEntities : DbContext, IContext
{
    public MockGolfEntities() {}

    public IDbSet<Golfer> Golfers { 
        get {
            return new InMemoryDbSet<Golfer>();
        }
        set {
            this.Golfers = this.Set<Golfer>();
        }
    }
}

set 方法通过将值分配给 this.Golfers 调用了自身。您应该将该值存储在某个地方。例如:this.golfers = value;,其中 golfers 是一个私有字段(private IDbSet<Golfer> golfers;)。 - Sam
1个回答

5
您不需要实现get/set,以下代码应该足以为您生成上下文。
public class MockGolfEntities : DbContext, IContext
{
    public MockGolfEntities() {}

    public IDbSet<Golfer> Golfers { get; set;}

}

我已经实现了你在原帖中提供的代码,一切似乎都很顺利 - 你从哪里获取了InMemoryDbSet的源代码?我使用的是NuGet包 1.3,也许你应该尝试这个版本?


谢谢-如果我想要实现集合,我仍然感到困惑,但我很高兴将魔法留给IDbSet。我意识到我的集合是疯狂的,因为我试图在无限循环中设置属性,但我很绝望,想发布一些代码来表明我至少尝试过:-)。我没有使用NuGet,但我正在尝试使用它。谢谢提供链接。 - The Jonas Persson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接