1. ホーム
  2. c#

[解決済み] MoqでEF DbContextをモック化する

2023-04-29 01:33:18

質問

モック化されたDbContextを使ったサービスのユニットテストを作成しようとしています。私はインターフェイスを作成しました IDbContext を作成し、以下のような機能を持たせました。

public interface IDbContext : IDisposable
{
    IDbSet<T> Set<T>() where T : class;
    DbEntityEntry<T> Entry<T>(T entity) where T : class;
    int SaveChanges();
}

私の実際のコンテキストは、このインターフェイスを実装しています IDbContext そして DbContext .

今、私は IDbSet<T> をモックしています。 List<User> を返します。

[TestMethod]
public void TestGetAllUsers()
{
    // Arrange
    var mock = new Mock<IDbContext>();
    mock.Setup(x => x.Set<User>())
        .Returns(new List<User>
        {
            new User { ID = 1 }
        });

    UserService userService = new UserService(mock.Object);

    // Act
    var allUsers = userService.GetAllUsers();

    // Assert
    Assert.AreEqual(1, allUsers.Count());
}

でいつもこのエラーが出ます。 .Returns :

The best overloaded method match for
'Moq.Language.IReturns<AuthAPI.Repositories.IDbContext,System.Data.Entity.IDbSet<AuthAPI.Models.Entities.User>>.Returns(System.Func<System.Data.Entity.IDbSet<AuthAPI.Models.Entities.User>>)'
has some invalid arguments

どのように解決するのですか?

私は、この問題を解決するために FakeDbSet<T> を実装したクラスを作成することで解決しました。 IDbSet<T>

public class FakeDbSet<T> : IDbSet<T> where T : class
{
    ObservableCollection<T> _data;
    IQueryable _query;

    public FakeDbSet()
    {
        _data = new ObservableCollection<T>();
        _query = _data.AsQueryable();
    }

    public virtual T Find(params object[] keyValues)
    {
        throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
    }

    public T Add(T item)
    {
        _data.Add(item);
        return item;
    }

    public T Remove(T item)
    {
        _data.Remove(item);
        return item;
    }

    public T Attach(T item)
    {
        _data.Add(item);
        return item;
    }

    public T Detach(T item)
    {
        _data.Remove(item);
        return item;
    }

    public T Create()
    {
        return Activator.CreateInstance<T>();
    }

    public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
    {
        return Activator.CreateInstance<TDerivedEntity>();
    }

    public ObservableCollection<T> Local
    {
        get { return _data; }
    }

    Type IQueryable.ElementType
    {
        get { return _query.ElementType; }
    }

    System.Linq.Expressions.Expression IQueryable.Expression
    {
        get { return _query.Expression; }
    }

    IQueryProvider IQueryable.Provider
    {
        get { return _query.Provider; }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _data.GetEnumerator();
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return _data.GetEnumerator();
    }
}

これで、私のテストは次のようになります。

[TestMethod]
public void TestGetAllUsers()
{
    //Arrange
    var mock = new Mock<IDbContext>();
    mock.Setup(x => x.Set<User>())
        .Returns(new FakeDbSet<User>
        {
            new User { ID = 1 }
        });

    UserService userService = new UserService(mock.Object);

    // Act
    var allUsers = userService.GetAllUsers();

    // Assert
    Assert.AreEqual(1, allUsers.Count());
}