簡體   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