在 C# 中使用 Moq 模拟服务
Mocking a Service using Moq in C#
我有一个以这种方式设置的服务。
public Interface IDataService : IDisposable
{
IQueryable<T> Set<T>() where T : class;
IDbSet<T> WritableSet<T>() where T : class;
}
IDataService被DataService继承。
public abstract class DataService : IDataService
{
public IDataContext DataContext { get; private set; }
public IQueryable<T> Set<T>() where T : class
{
return DataContext.Set<T>().AsNoTracking();
}
public IDbSet<T> WritableSet<T>() where T : class
{
return DataContext.Set<T>();
}
public AddResult<T> Add<T>(T obj) where T : class, IPersistentEntity
{
if (obj == null)
return new AddResult<T>() { IsValid = false };
else
{
if (obj.Id == Guid.Empty)
WritableSet<T>().Add(obj);
bool success = DataContext.SaveChanges() > 0;
return new AddResult<T>() { Entity = obj, IsValid = success };
}
}
}
并且DataService被EntityService继承。
public class EntityService : DataService
{
public EntityService(IDataContext DataContext) : base(DataContext)
{
}
public void EntityStarted(Guid Id)
{
var a = GetWriteableById<Entity>(Id);
a.Status = 1;
DataContext.SaveChanges();
}
}
我的一个组件中使用了此 EntityService。 EntityService 的对象已创建并传递给组件的构造函数。
我正在使用 Moq 对组件执行一些测试,为此,计划是模拟 EntityService,以便 EntityService 使用带有虚拟数据的假数据库容器进行类似数据库的操作。但是,我没有最好的主意来用最少的新代码来模拟它。
我最没有吸引力的想法是使用接口创建一个假的 EntityService class 并拥有适合测试的自己的实现。
感谢帮助! :)
要模拟您需要一个接口,如果没有,您需要将要模拟的方法标记为虚拟方法。
在幕后,模拟框架将为您创建一个新的实现,其行为与您配置的模拟相同。
希望对您有所帮助。
根据@JLe 和@Chetan 对该问题的评论,我不得不模拟 DbContext。
我按照这篇文章模拟了 DbContext。
代码如下所示。
private void Setup()
{
List<Entity> entityData = new List<Entity>();
entityData.Add(new Entity
{
Id = Guid.NewGuid()
});
DbSet<Entity> MockEntitySet = GetSet(entityData);
MockContext = new Mock<IDbContext>();
MockContext.Setup(m => m.Set<Entity>()).Returns(MockEntitySet);
}
public static DbSet<T> GetSet<T>(List<T> sourceList) where T : class
{
return GetSet(sourceList.ToArray());
}
public static DbSet<T> GetSet<T>(T[] sourceList) where T : class
{
var name = typeof(T).Name;
var queryable = sourceList.AsQueryable();
Mock<DbSet<T>> dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
dbSet.Setup(m => m.AsNoTracking()).Returns(dbSet.Object);
return dbSet.Object;
}
[TestMethod]
public void Test()
{
EntityService service = new EntityService(MockContext.Object);
ComponentToTest compObj = new ComponentToTest(service);
compObj.MethodToTest(...);
// Assertions
}
谢谢大家!感谢您的帮助和建议。
我有一个以这种方式设置的服务。
public Interface IDataService : IDisposable
{
IQueryable<T> Set<T>() where T : class;
IDbSet<T> WritableSet<T>() where T : class;
}
IDataService被DataService继承。
public abstract class DataService : IDataService
{
public IDataContext DataContext { get; private set; }
public IQueryable<T> Set<T>() where T : class
{
return DataContext.Set<T>().AsNoTracking();
}
public IDbSet<T> WritableSet<T>() where T : class
{
return DataContext.Set<T>();
}
public AddResult<T> Add<T>(T obj) where T : class, IPersistentEntity
{
if (obj == null)
return new AddResult<T>() { IsValid = false };
else
{
if (obj.Id == Guid.Empty)
WritableSet<T>().Add(obj);
bool success = DataContext.SaveChanges() > 0;
return new AddResult<T>() { Entity = obj, IsValid = success };
}
}
}
并且DataService被EntityService继承。
public class EntityService : DataService
{
public EntityService(IDataContext DataContext) : base(DataContext)
{
}
public void EntityStarted(Guid Id)
{
var a = GetWriteableById<Entity>(Id);
a.Status = 1;
DataContext.SaveChanges();
}
}
我的一个组件中使用了此 EntityService。 EntityService 的对象已创建并传递给组件的构造函数。
我正在使用 Moq 对组件执行一些测试,为此,计划是模拟 EntityService,以便 EntityService 使用带有虚拟数据的假数据库容器进行类似数据库的操作。但是,我没有最好的主意来用最少的新代码来模拟它。
我最没有吸引力的想法是使用接口创建一个假的 EntityService class 并拥有适合测试的自己的实现。
感谢帮助! :)
要模拟您需要一个接口,如果没有,您需要将要模拟的方法标记为虚拟方法。
在幕后,模拟框架将为您创建一个新的实现,其行为与您配置的模拟相同。
希望对您有所帮助。
根据@JLe 和@Chetan 对该问题的评论,我不得不模拟 DbContext。 我按照这篇文章模拟了 DbContext。
代码如下所示。
private void Setup()
{
List<Entity> entityData = new List<Entity>();
entityData.Add(new Entity
{
Id = Guid.NewGuid()
});
DbSet<Entity> MockEntitySet = GetSet(entityData);
MockContext = new Mock<IDbContext>();
MockContext.Setup(m => m.Set<Entity>()).Returns(MockEntitySet);
}
public static DbSet<T> GetSet<T>(List<T> sourceList) where T : class
{
return GetSet(sourceList.ToArray());
}
public static DbSet<T> GetSet<T>(T[] sourceList) where T : class
{
var name = typeof(T).Name;
var queryable = sourceList.AsQueryable();
Mock<DbSet<T>> dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
dbSet.Setup(m => m.AsNoTracking()).Returns(dbSet.Object);
return dbSet.Object;
}
[TestMethod]
public void Test()
{
EntityService service = new EntityService(MockContext.Object);
ComponentToTest compObj = new ComponentToTest(service);
compObj.MethodToTest(...);
// Assertions
}
谢谢大家!感谢您的帮助和建议。