我想为一个包含linq-sql代码的类编写单元测试。我的意思是,在每个方法中,我都创建了一个新的DbContext并完成了数据库工作。
我在网上搜索了一下。首先我开始使用存储库和工作单元模式,但我发现DbContext本身是一个工作单元,它的dbset作为存储库工作。另一点是,我认为没有必要测试Linq部分,因为它可以正常工作(由.net团队测试)。我想测试我添加到代码中的逻辑。所以我决定用两个实现创建一个带有必要方法的接口,一个使用linqToSql,而另一个只是一个mock。像这样的东西:
public interface IDbManager
{
bool Insert(MyEntity newEntity);
}
public class RealDbManager:IDbManager
{
public bool Insert(MyEntity newEntity)
{
using (DbDataContext db = new DbDataContext())
{
db.MyEntities.InsertOnSubmit(newEntity);
db.SubmitChanges();
}
}
}
public class MockDbManager:IDbManager
{
public bool Insert(MyEntity newEntity)
{
return true;
}
}
整个想法正确吗?如果是,这是一个正确的实现吗?
是否可以将DbDataContext定义为类变量,而不是在每个方法中创建新实例?
您已经有了正确的总体思路。Mock Insert
方法应该将实体保存到内存中的某个存储中,以便后续查询将返回插入的信息,正如预期的那样。但是,有一个接口的基本思想,一个"真实"和一个"模拟"实现是存在的。
请记住,在测试中使用Mock时,您正在测试使用Mock的其他代码,而不是Mock本身。
至于将DataContext定义为成员变量;你可以使用一个IDisposable模式,比如:
public class RealDbManager:IDbManager, IDisposable
{
DbDataContext db = new DbDataContext();
public bool Insert(MyEntity newEntity)
{
{
db.MyEntities.InsertOnSubmit(newEntity);
db.SubmitChanges();
}
}
public void Dispose()
{
db.Dispose();
}
}
那么,你只需要确保处理掉你的DbManager。
是。我唯一要避免的是创建一个实际的模拟类(在这种情况下,它应该被称为Fake),但要使用模拟引擎。
在你的问题中,你提到了两种测试。首先是测试类的行为,其次是测试它的集成。它们看起来是一样的,但事实并非如此。
首先,你需要模拟你的类,以这种方式(使用Moq)测试它与其他类的"连接":
[Test]
public void Test()
{
var entity = new Entity();
var mocked = new Mock<IDbManager>();
//you are telling the moq engine everytimes it finds an invocation of your repository
//to return true as you did in you mocked class
mocked.Setup( x => x.Insert( entity ) ).Returns( true );
var classUnderTest = new ClassUnderTest( mocked.Object );
//in this method you invoke your repository
var ret = classUnderTest.DoSomething( entity );
//assertions
Assert.Equal( something, ret);
//eventually you can verify that your repository has been hit once
mocked.Verify( x => x.Insert( It.IsAny<Entity>), Times.Once);
}
稍后,正如您正确指出的那样,您在linq上没有什么可测试的(微软为我们做了这件事),但如果您需要验证linq的正确性,您只能针对真实的数据库(或使用存储库模式针对伪造的存储库)进行测试。这是一个集成测试,它与嘲讽无关。
若要将类与DbContext解耦,可以使用存储库模式。看看这篇文章。http://dotnetspeak.com/index.php/2011/03/repository-pattern-with-entity-framework/