测试数据库调用C#

首先,让我们在这里解决术语。 我搜索的所有内容都说:“unit testing不会触及数据库!” 我不想进行unit testing。 我想要一个测试,当我将数据发送到数据库时,我知道它正确地保存了它(以及测试其他crud操作)。 我有一个基本上接受DTO的存储库层,然后将该DTO映射到entity framework模型,然后将该模型保存到数据库。

我需要能够确保将DTO发送到这些方法实际上是保存到数据库中。

存储库上的示例方法签名是:

public bool Save(SomeObjectDTO someObject) 

我只需要测试此方法调用是否返回true。

设置测试的最佳方法是将调用的方法保存到数据库中?

此外,是否有标准的方法来设置空白测试数据库? 如果我点击“运行测试”它会构造一个空数据库,用必要的初始数据填充它,然后执行所有CRUD操作(我的所有存储库调用)以查看它们都像它们一样保存,那将是很棒的应该。

如果这已经得到了回答,我表示歉意,但是我搜索到的所有内容都有人说你不应该测试数据库调用,或者人们在谈论嘲笑这些在这里真的没用。

我只想要一个关于如何设置这些类型的测试的示例和/或标准实践。

您正在寻找的是集成测试,它与编写unit testing同样重要。 您的底层数据提供程序会暴露许多潜在的错误,即模拟您的存储库不一定会找到(无效的外键,标记为非空的内容的空数据等)。

我认为对您的生产系统进行相同的数据库提供程序测试也很重要,否则可能会丢失特定于实现的行为。 我将Azure SQL用于项目,而不是创建内存中的SQL CE实例,我在Azure上有一个单独的数据库,它仅用于我的集成测试。

如果你使用XUnit(并且我确定它存在于其他测试框架中),那么有一个方便的属性[AutoRollback]会在每次测试运行后自动回滚你的事务。

 [Fact] [AutoRollback] public void AddProductTest_AddsProductAndRetrievesItFromTheDatabase() { // connect to your test db YourDbContext dbContext = new YourDbContext("TestConnectionString") dbContext.Products.Add(new Product(...)); // get the recently added product (or whatever your query is) var result = dbContext.Single(); // assert everything saved correctly Assert.Equals(...); } 

测试完成后,您的数据库将再次处于空白状态(或者在运行测试之前的任何状态)。

要在使用EntityFramework时对数据库进行测试,请按以下步骤操作:

首先,如果需要,我定义将使用ObjectContext的工厂访问ObjectContext的类:在我的情况下,我在NT服务中工作,因此上下文在请求期间或其他范围内不存在:YMMV但是如果您正在测试一个组件,那么您可以完全隔离而不会有太多麻烦,因为您在Web中的上下文工厂肯定会从请求中获取上下文:只是不要在DAL类中初始化/关闭它。

 public DataAccessClass: IWorkOnStuff { public Func DataAccessFactory { get; internal set; } private string ConnectionString; public PortailPatientManagerImplementation(string connectionString) { ConnectionString = connectionString; DataAccessFactory = () => { return new DataEntities(ConnectionString); }; } /* interface methods */ public IEnumerable GetTheStuff(SomeParameters params) { using (var context = DataAccessFactory()) { return context.Stuff.Where(stuff => params.Match(stuff)); } } } 

现在,有趣的是,当您想要测试它时,您可以使用名为Effort的库 ,它允许您在内存中映射数据库。 要做到这一点,只需创建您的类,并在测试设置中告诉Effort从这里获取它:

 public class TestDataAccessClass { public DataAccessClass Target { get; set; } protected int Calls = 0; protected DataEntities DE; [SetUp] public void before_each_test() { Target = new DataAccessClass(string.Empty); Calls = 0; FullAccessCalls = 0; var fakeConnection = "metadata=res://*/bla.csdl|res://*/bla.ssdl|res://*/bla.msl;provider=System.Data.SqlClient"; DE = Effort.ObjectContextFactory.CreateTransient(fakeConnection); Target.DataAccessFactory = () => { Calls++; return DE; }; SetupSomeTestData(DE); } } 

SetupSomeTestData只需添加所需的实体(引用等),现在您可以调用方法以确保数据确实来自您在设置中定义的ObjectContext。

有趣的是,正如mfanto所说,这是一个集成测试,而不是unit testing,但正如他自己所说 :

这对我来说听起来不像是单元而是集成测试!

你是对的,我在标题中使用术语“unit testing”,因为SEO的原因:)同时大多数人似乎并不知道它们之间的差异。

我不知道这是否是测试entity frameworkDAL的最佳方法; 我花了一些时间来实现这个解决方案,我发现它并非没有优点,但我会看到这个问题,以便了解提出的其他解决方案。