我正在使用Code First将类映射到现有数据库。我需要一种方法来对这些映射进行单元测试,这些映射是基于约定,基于属性和流畅的api的混合。
要进行单元测试,我需要确认类的属性映射到数据库中正确的表名和列名。此测试需要针对上下文执行,并且应首先涵盖代码的所有配置选项。
在非常高的层面上,我想要断言像(伪代码):
Assert.IsTrue(context.TableFor<Widget>().IsNamed("tbl_Widget"));
Assert.IsTrue(context.ColumnFor<Widget>(w => w.Property).IsNamed("WidgetProperty"));
答案 0 :(得分:1)
要考虑的另一个想法是使用Linq和ToString()。
例如:
context.Widget.Select(c => c.Property).ToString()
将导致SQL Server提供程序:
"SELECT [Var_3].[WidgetProperty] AS [WidgetProperty] FROM [dbo].[Widget]..."
现在我们可以在一些Extension方法中隐藏它,并解析生成的SQL,它看起来几乎就像你的伪代码:
Assert.IsTrue(context.Widgets.GetSqlColumnNameFor(w => w.Property).IsNamed("WidgetProperty"));
延期草案:
public string GetSqlColumnNameFor<TSource>(this DbSet<T> source, Expression<Func<TSource, TResult>> selector)
{
var sql = source.Select(selector).ToString();
var columnName = sql... // TODO : Some regex parsing
return
columnName;
}
类似我们可以创建GetSqlTableNameFor()。
更新:我决定寻找一些专用的SQL Parsers,所以这个解决方案更通用,显然.NET有这样的东西:
答案 1 :(得分:0)
我能想到涵盖所有可能选项的唯一方法是使用Entity Framework Power Tools预编译DbContext的视图,并且可能使用生成类型的反射和生成的RegEx的组合代码本身以验证所有地图以您希望的方式映射。听起来很痛苦。
我想到的另一件事是围绕DbModelBuilder创建一个外观来拦截和检查通过它的所有内容,但我不知道是否会处理基于约定的内容。听起来也很痛苦。
作为一个不太完整但更容易的替代方案,你可以通过尽可能切换到基于属性的映射来淘汰其中很大一部分。这将允许您创建一个基本测试类,比如ModelTesting&lt; TEntity&gt;,其中包含一些使用反射来验证TEntity的测试方法:
您甚至可以根据属性和类的名称强制执行命名约定(对每个层次结构的表类型有一个警告)。也可以检查外键映射。这是一个一次写入的基类,你可以从每个模型类型中获得一次,并捕获大部分错误(好吧,无论如何,它都占据了我的大多数)。
任何不能由属性表示的东西,比如TPH继承等,都会变得有点困难。如果您的DbContext不为您生成数据库,那么启动DbContext并在Set&lt; TEntity&gt;()上执行FirstOrDefault的集成测试可能会覆盖大部分基数。
答案 2 :(得分:0)
如果你写了一个方法
public static string ToMappingString(this Widget obj)
然后您可以通过批准测试(www.approvaltests.com或nuget)轻松测试这个
这里有一段视频:http://www.youtube.com/watch?v=vKLUycNLhgc
但是,如果您要测试“我的对象保存并自行检索” 那么这是“基于理论的测试”的理想之地
基于理论的测试 大多数单元测试采用
的形式Given A,B expect C
基于理论的测试
Given A,B expect Theory
这样的美妙之处在于无需担心哪种特殊形式A&amp; B因为你不需要知道C,所以任何随机发生器都可以工作。
示例1:测试添加和减去方法
通常你会有像
这样的东西Assert.AreEqual(5, Add(2,3));
Assert.AreEqual(9, Add(10,-1));
Assert.AreEqual(10, Add(5,5));
Assert.AreEqual(7, Subtract(10,3));
但是,如果你写了一个理论测试,它看起来像
for(int i = 1; i < 100; i++)
{
int a = random.Next();
int b = random.Next();
Assert.AreEqual(a, Subtract(Add(a,b),b, string.Format("Failed for [a,b] = [{0},{1}], a,b));
}
现在您已了解基于理论的测试,您尝试测试的理论是
Given Model A
When A is stored to the database, and retrieved the resulting object is equal to A