首先,让我们在这里解决术语。我搜索的所有东西都说,"单元测试不会触及数据库!"我不想进行单元测试。我想要一个测试,当我将数据发送到数据库时,我知道它正确地保存了它(以及测试其他crud操作)。我有一个基本上接受DTO的存储库层,然后将该DTO映射到实体框架模型,然后将该模型保存到数据库中。
我需要能够确保将DTO发送到这些方法实际上是保存到数据库中。
存储库上的示例方法签名是:
public bool Save(SomeObjectDTO someObject)
我只需要测试此方法调用是否返回true。
设置测试的最佳方法是,我的方法被调用的是保存到数据库的方法吗?
此外,是否有标准的方法来设置空白测试数据库?如果我点击"运行测试"那将是很好的。它构造一个空数据库,用必要的初始数据填充它,然后执行所有CRUD操作(我的所有存储库调用),看看它们都像它们一样保存。
我很抱歉,如果已经回答了这个问题,但我搜索的所有内容都有人说你不应该测试数据库调用,或者有人在谈论嘲笑这些在这里没有用的东西。
我只想了解如何设置这些类型的测试的示例和/或标准练习。
答案 0 :(得分:2)
您正在寻找的内容称为集成测试,与编写单元测试同样重要。您的基础数据提供程序暴露了很多潜在的错误,模拟您的存储库不一定会找到(无效的外键,标记为非空的内容的空数据等)。
我认为您对与生产系统相同的数据库提供程序进行测试也很重要,否则存在缺少实现特定行为的风险。我将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(...);
}
测试完成后,您的数据库将再次处于空白状态(或者在运行测试之前的状态)。
答案 1 :(得分:1)
在使用EntityFramework时对数据库进行测试,以下是我的演绎方法:
首先,如果需要,我定义将使用ObjectContext
工厂访问ObjectContext
的类:在我的情况下,我在NT服务中工作,因此上下文没有'在请求或其他范围内生存:YMMV但是如果您正在测试组件,您可以完全隔离而不会有太多麻烦,因为您的工厂在Web中的上下文肯定会从请求中获取上下文:只需要#&# 39;在你的DAL课程中初始化/关闭它。
public DataAccessClass: IWorkOnStuff
{
public Func<DataEntities> DataAccessFactory { get; internal set; }
private string ConnectionString;
public PortailPatientManagerImplementation(string connectionString)
{
ConnectionString = connectionString;
DataAccessFactory = () => { return new DataEntities(ConnectionString); };
}
/* interface methods */
public IEnumerable<Stuff> GetTheStuff(SomeParameters params)
{
using (var context = DataAccessFactory())
{
return context.Stuff.Where(stuff => params.Match(stuff));
}
}
}
现在,有趣的是,当你想测试它时,可以使用a library called 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<DataEntities>(fakeConnection);
Target.DataAccessFactory = () => { Calls++; return DE; };
SetupSomeTestData(DE);
}
}
在SetupSomeTestData
中添加您想要的实体(引用等),现在您可以调用您的方法以确保您的数据确实来自您设置中定义的ObjectContext。
有趣的是,正如mfanto所说,这是一个集成测试,不是单元测试,而是as he says it himself:
这听起来不像是单位,而是对我进行集成测试!
你是对的,我使用术语&#34;单元测试&#34;在标题中因为 SEO的原因:)大多数人似乎都不知道 他们之间的差异。
我不知道这是否是针对实体框架DAL进行测试的最佳方式;我花了一些时间来实现这个解决方案,我发现它并非没有优点,但我会看到这个问题,以便了解其他解决方案的建议。