繁体   English   中英

如何用具体类型模拟ITable

[英]how to mock ITable with a concrete type

我正在为使用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);

Forum是一个自动生成的类。 我想设置Table的论坛,这样当我在ContextWrapper上做一个GetTable时,我得到了论坛表。 我不知道Table.Attach是否会将论坛附加到桌面上。 当我运行测试时,它说

'类型为mock必须是接口或抽象类或非密封类'。

我弄错了吗?

我看到你正在尝试做的几个问题。

  1. 发布的代码无法编译

    IDataContextWrapper.GetTable返回Table<T> ,因此您无法将其设置为返回ITable<T> ITable 不是 Table ,而是另一种方式。 这引出了我的下一点:

  2. IDataContextWrapper.GetTable应返回ITable<T> ,而不是Table<T>

    这将让你模拟返回结果,因为Table<T>密封的 (Moq不能模拟密封类,这可能是你得到你提到的错误的原因)。 编程接口而不是混凝土也是很好的设计。

  3. 你不应该期望对Attach的调用做任何事情

    你试图在一个模拟的界面上调用一个方法,就像你期望它表现得像某个东西已经实现它一样。 mock的方法只会按照你告诉他们的方式执行,因此在这种情况下(使用Loose行为 )它将不会对该调用执行任何操作。 相反,你应该设置你希望表格做什么,但这导致我:

  4. 您无法将调用设置为Single因为它是一种扩展方法

    Moq 不支持设置扩展方法 ,因为它们是静态方法。 但是,您可以设置对GetEnumerator的调用,这是Single调用的。 你需要模拟IQueryable<T>成员 ,因为那是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);
}

请注意,这是一个很好的,不是很好的测试。 您可以通过调用First替换对Single的调用,它仍会通过,但显然通常是错误的。 您至少应该添加此测试的否定,即如果Id不匹配则不返回任何对象。

尝试这样的事情

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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM