Mar*_*ith 15 linq tdd unit-testing moq entity-framework-4.1
我正在使用EF 4.1来构建域模型.我有一个带有Validate(字符串userCode)方法的Task类,在其中我想确保用户代码映射到数据库中的有效用户,因此:
public static bool Validate(string userCode)
{
IDbSet<User> users = db.Set<User>();
var results = from u in users
where u.UserCode.Equals(userCode)
select u;
return results.FirstOrDefault() != null;
}
Run Code Online (Sandbox Code Playgroud)
我可以使用Moq来模拟IDbSet没问题.但是在Where调用时遇到了麻烦:
User user = new User { UserCode = "abc" };
IList<User> list = new List<User> { user };
var users = new Mock<IDbSet<User>>();
users.Setup(x => x.Where(It.IsAny<Expression<Func<User, bool>>>())).Returns(list.AsQueryable);
Initialization method JLTi.iRIS3.Tests.TaskTest.SetUp threw exception.
System.NotSupportedException: System.NotSupportedException: Expression
references a method that does not belong to the mocked object:
x => x.Where<User>(It.IsAny<Expression`1>()).
Run Code Online (Sandbox Code Playgroud)
除了创建一个间接级别(例如,使用ServiceLocator来获取运行LINQ的对象然后模拟该方法)之外,我想不出怎么测试这个,但我想确保以前没办法我介绍另一层.而且我可以看到经常需要这种LINQ查询,因此服务对象很快就会失控.
某种灵魂有帮助吗?谢谢!
Ale*_*ith 20
有一篇关于MSDN的文章突出显示了如何使用moq进行模拟:它的要点是将linq表示为具有linq到对象的实体操作.
var mockSet = new Mock<DbSet<Blog>>();
mockSet.As<IQueryable<Blog>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Blog>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Blog>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Blog>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
Run Code Online (Sandbox Code Playgroud)
正如Ladislav所指出的那样,由于Linq To Objects与Linq to Entities的不同,因此可能会导致误报.但它现在是一篇MSDN文章,它确实指出它至少是可能的,也许在某些情况下推荐?
自从这篇文章的原始答案以来可能发生的一件事是,实体框架团队已经在EF 6.0中开辟了实体框架领域,以便更容易模仿它的内部.
aqw*_*ert 10
虽然我没有尝试过这个,但是因为IDBSet实现IEnumerable你可能需要模拟枚举器方法,所以linq语句会选择你的用户列表.您实际上并不想模拟linq,但是根据代码的外观,您要测试是否根据UserCode我认为是有效的单元测试来找到合适的用户.
var user = new User { UserCode = "abc" };
var list = new List<User> { user };
var users = new Mock<IDbSet<User>>();
users.Setup(x => x.GetEnumerator()).Returns(list.GetEnumerator());
Run Code Online (Sandbox Code Playgroud)
您可能会与非通用版本发生冲突,GetEnumerator但这可能会帮助您走上正确的道路.然后,您必须将模拟对象放在数据上下文中,这取决于我们看不到的其他代码.
据我所知,Moq只能设置模拟对象本身的虚方法,但是你试图设置扩展(静态)方法 - 没办法!这些方法绝对不在您的模拟范围之内.
此外,该代码很难测试,需要太多的初始化才能测试它.请改用:
internal virtual IQueryable<User> GetUserSet()
{
return db.Set<User>();
}
public bool Validate(string userCode)
{
IQueryable<User> users = GetUserSet();
var results = from u in users
where u.UserCode.Equals(userCode)
select u;
return results.FirstOrDefault() != null;
}
Run Code Online (Sandbox Code Playgroud)
您只需要设置GetUserSet返回列表即可.此类测试存在一些主要问题:
Include因为include依赖于DbQuery/ DbSet.您需要进行集成测试才能使用它.更好的方法是从Validate方法中删除linq查询- 只需将它们称为对象的另一个虚方法.Validate使用模拟查询方法对您的方法进行单元测试,并使用集成测试来自行测试查询.
| 归档时间: |
|
| 查看次数: |
20122 次 |
| 最近记录: |