我是嘲笑和使用Moq的新手。这是我第一次尝试模拟添加功能。我有mocks设置,它适用于读取函数,但是当我尝试对add方法进行单元测试时,它会将更改保存到db。
如何模拟添加方法?
我想我必须模拟我的UnitOfWork
类,它具有SaveChanges()
方法。我想知道如何设置模拟来拦截对SaveChanges()
的调用而不是保存到db。
这是我到目前为止的模拟
[SetUp]
public void SetUp()
{
addCount = 0;
IEnumerable<Platform> platformList = new List<Platform>(){
new Platform() { Id = 1, Name = "Unknown"},
new Platform() { Id =2, Name = "Amazon"},
new Platform() { Id = 3, Name = "Prime Pantry"}
};
var platformData = platformList.AsQueryable();
var mockPlatformSet = new Mock<DbSet<Platform>>();
mockPlatformSet.As<IQueryable<Platform>>().Setup(m => m.Provider).Returns(platformData.Provider);
mockPlatformSet.As<IQueryable<Platform>>().Setup(m => m.Expression).Returns(platformData.Expression);
mockPlatformSet.As<IQueryable<Platform>>().Setup(m => m.ElementType).Returns(platformData.ElementType);
mockPlatformSet.As<IQueryable<Platform>>().Setup(m => m.GetEnumerator()).Returns(platformData.GetEnumerator());
mockPlatformSet.Setup(m => m.Add(It.IsAny<Platform>())).Callback(() => addCount++);
var mockContext = new Mock<ApplicationDbContext>(){ CallBase = true };
mockContext.Setup(m => m.Platforms).Returns(mockPlatformSet.Object);
mockContext.Setup(m => m.Platforms.Add(It.IsAny<Platform>()));
mockContext.Setup(m => m.Platforms.Add(It.IsAny<Platform>())).Callback(() => addCount++);
unitOfWork = new UnitOfWork(mockContext.Object);
platformRepo = new PlatformRepository(mockContext.Object);
controller = new PlatformController(platformRepo, unitOfWork);
}
添加UnitOfWork代码
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
private bool _isDisposed = false;
public UnitOfWork(DbContext context)
{
_context = context;
}
public void SaveChanges()
{
_context.SaveChanges();
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
_context.Dispose();
}
}
_isDisposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
更新了问题
我正在尝试对我Create
的{{1}}方法进行单元测试。在此方法中,我在repostiory上调用PlatformController
函数,然后调用Add
SaveChanges
函数。我想验证我的UnitOfWork
对象是否被添加到DbSet,但是“拦截”对Platform
的调用,它不会写入db。
我该怎么做?
答案 0 :(得分:5)
当我将CallBase
的{{1}}值设置为mockContext
到IUnitOfWork
时,这似乎解决了我的单元测试写入数据库的问题。< / p>
这行代码:
false
以下是我的mockContext.As<IUnitOfWork>().CallBase = false;
功能
Setup
答案 1 :(得分:3)
我不确定这是你正在寻找的答案,但用工作单位抽象EF DbContext
是个糟糕的主意。原因是上下文已经 是一个工作单元实现。根据{{3}}中的课程描述:
表示工作单元和存储库模式的组合 并使您能够查询数据库并将更改组合在一起 然后将作为一个单元写回商店。
删除不必要的抽象后,模拟上下文应该相当容易,特别是如果您使用最新版本的Entity Framework。
答案 2 :(得分:-1)
您在这里尝试进行功能测试,因此拥有一个功能数据库是明智的。
EF可以使用测试连接字符串在setup和teardown方法中重新创建和销毁数据库。这将为您的测试提供真实的功能测试环境,以防止模仿真实环境。
例如:
[TestFixtureSetUp]
public static void SetupFixture() //create database
{
using (var context = new XEntities())
{
context.Setup();
}
}
[TestFixtureTearDown]
public void TearDown() //drop database
{
using (var context = new XEntities())
{
context.Database.Delete();
}
}
[SetUp]
public void Setup() //Clear entities before each test so they are independent
{
using (var context = new XEntities())
{
foreach (var tableRow in context.Table)
{
context.Table.Remove(tableRow);
}
context.SaveChanges();
}
}
更改测试项目中的连接字符串以指向&#34; DbNameTest&#34;并且你在测试中使用你的XEntities类是很好的,并且很容易设置和添加测试数据来与之交互。