我正在为使用System.Data.Linq DataConext对象从数据库获取实体表的存储库编写单元测试。下面是代码:
public class ForumRepository : IForumRepository
{
protected Table<Forum> DataTable;
IDataContextWrapper DataContext;
public ForumRepository(IDataContextWrapper DataContext)
{
DataTable = DataContext.GetTable<Forum>();
}
public Forum GetForumById(int id)
{
try
{
return DataTable.Single(f => f.tblForumID.Equals(id));
}
catch(Exception e)
{
return null;
}
}下面是包装器的实现:
public class DataContextWrapper<T> : IDataContextWrapper where T : EpixForumDataContext, new()
{
private readonly T db;
public DataContextWrapper()
{
var t = typeof(T);
db = (T)Activator.CreateInstance(t);
}
public DataContextWrapper(string connectionString)
{
var t = typeof(T);
db = (T)Activator.CreateInstance(t, connectionString);
}
public Table<TableName> GetTable<TableName>() where TableName : class
{
return (Table<TableName>)db.GetTable(typeof(TableName));
}我想测试存储库方法。
public class UnitTest1
{
[TestMethod]
public void Can_Get_Forum_ById()
{
//arrange
Forum dummyForum = new Forum() { tblForumID = 1};
Mock<ITable<Forum>> tableMock = new Mock<ITable<Forum>>();
tableMock.Object.Attach(dummyForum);
Mock<IDataContextWrapper> mock = new Mock<IDataContextWrapper>();
mock.Setup(m => m.GetTable<Forum>()).Returns(tableMock.Object) ;
//act
ForumRepository repos = new ForumRepository(mock.Object);
Forum resultForum = repos.GetForumById(1);
//assert
Assert.AreEqual(resultForum.tblForumID, 1);其中论坛是一个自动生成的类。我想为表格设置论坛,这样当我在GetTable上做ContextWrapper时,我就会得到论坛的表格。我不知道Table.Attach是否会把论坛附加到桌面上。另外,当我运行测试时,上面写着
“要模拟的类型必须是接口、抽象类或非密封类”。
我搞错了吗?
发布于 2014-08-15 13:12:28
我看到你想做的事有几个问题。
IDataContextWrapper.GetTable返回Table<T>,因此不能将其设置为返回模拟的ITable<T>。ITable不是Table,而是相反。这就引出了我的下一个观点:IDataContextWrapper.GetTable应该返回一个ITable<T>,而不是Table<T>。
这将允许您模拟返回结果,因为Table<T>是密封的 (Moq不能模拟密封类,这可能就是您得到所提到的错误的原因)。它也是程序接口的好设计,而不是混凝土设计。Attach的调用会做任何事情
您试图在模拟的接口上调用一个方法,就像您期望它表现得好像有什么东西已经实现了一样。模拟的方法只执行您让他们做的事情,因此在本例中(使用松散行为),它将不会对该调用进行任何操作。相反,您应该设置您希望该表执行的操作,但这将导致我注意到:Single的调用,因为它是一个扩展方法
Moq 不支持设置扩展方法,因为它们是静态方法。但是,您可以设置对GetEnumerator的调用,这也是Single所称的。不过,您需要成员,因为这正是Single真正要达到的目标。因此,在解决了上面的第1点之后,您的测试最终应该如下所示:
[Test]
public void Can_Get_Forum_ById()
{
// arrange
Forum dummyForum = new Forum { tblForumID = 1 };
IQueryable<Forum> forums = new List<Forum> { dummyForum }.AsQueryable();
Mock<ITable<Forum>> tableMock = new Mock<ITable<Forum>>();
tableMock.Setup(p => p.GetEnumerator()).Returns(forums.GetEnumerator());
tableMock.Setup(r => r.Provider).Returns(forums.Provider);
tableMock.Setup(r => r.ElementType).Returns(forums.ElementType);
tableMock.Setup(r => r.Expression).Returns(forums.Expression);
Mock<IDataContextWrapper> mock = new Mock<IDataContextWrapper>();
mock.Setup(m => m.GetTable<Forum>()).Returns(tableMock.Object);
// act
ForumRepository repos = new ForumRepository(mock.Object);
Forum resultForum = repos.GetForumById(1);
// assert
Assert.AreEqual(resultForum.tblForumID, 1);
}请注意,这是一个好的,不是很好的测试。您可以将对Single的调用替换为对First的调用,它仍然会通过,但显然是错误的。您至少应该添加此测试的否定项,即如果Id不匹配,则不返回任何对象。
发布于 2014-08-14 18:05:57
试试像这样的东西
Forum dummyForum = new Forum() { tblForumID = 1};
Mock<ITable> tableMock = new Mock<ITable>();
tableMock.Object.Attach(dummyForum);
Mock<IDataContextWrapper> contextMock = new Mock<IDataContextWrapper>();
contextMock .Setup(m => m.GetTable<Forum>()).Returns((ITable<Forum>)tableMock.Object) ;
//act
ForumRepository repos = new ForumRepository(mock.Object);
Forum resultForum = repos.GetForumById(1);
//assert
Assert.AreEqual(resultForum.tblForumID, 1);https://stackoverflow.com/questions/25313411
复制相似问题