9

我有一個簡單的文件管理器,它被注入到我的控制器在asp.net c#MVC項目中。該項目以數據庫優先,Document表索引爲documentId,一個自動遞增整數。我可以創建一個模擬數據庫上下文,我可以添加,然後搜索?

我一直在試圖編寫一個測試,測試以下實現CreateNewDocument,它在成功添加文檔後查找並返回新的文檔ID。

問題是,我找不到方法來模擬MyEntityFrameWorkEntities,我可以添加一個文檔,然後使用linq搜索該文檔。我認爲它不起作用,因爲嘲諷的_context.Document.Add沒有真正做任何事情。

我的問題是這樣的:我需要改變我的DocumentManager,這樣的代碼是(通過與.FirstOrDefault更換.First並顯示,如果返回null函數返回零例如)可測試的,或者我可以(我應該)集不同的我的嘲笑,所以我可以離開DocumentManager照原樣,並寫一個測試通過?

public class DocumentManager : IDocumentManager 
{ 
    private readonly MyEntityFrameWorkEntities _context; 

    public DocumentManager(MyEntityFrameWorkEntities context) 
    { 
     _context = context; 
    } 

    public int CreateNewDocument(int userId) 
    { 
     var newDocumentGuid = Guid.NewGuid(); 
     var newDocument = new Document 
     { 
      UserId = userId, 
      DateCreated = DateTime.Now, 
      DocumentGuid = newDocumentGuid 
     }; 
     _context.Document.Add(newDocument); 
     _context.SaveChanges(); 
     // the .First here doesn't return anything when called from tests 
     return _context.Document.First(d => d.DocumentGuid == newDocumentGuid).DocumentId; 
    } 
} 

public partial class MyEntityFrameWorkEntities : DbContext 
{ 
    public MyEntityFrameWorkEntities() : base("name=MyEntityFrameWorkEntities") 
    { 
    } 

    public virtual DbSet<Document> Document { get; set; } 
    /* ...etc... */ 
} 

和測試類:

[TestMethod] 
public void TestCreateNewDocument() 
{ 
    var mockContext = new Mock<MyEntityFrameWorkEntities>(); 

    var mockDocumentDbSet = GetQueryableMockDocumentDbSet(); 

    mockContext.Setup(m => m.Document).Returns(mockDocumentDbSet.Object); 

    var documentManager = new DocumentManager(mockContext.Object); 

    var newDocId = documentManager.CreateNewDocument2(123); 

    // This line doesn't get hit as the .First falls over before here 
    Assert.AreNotEqual(newDocId, 0); 
} 

private static Mock<DbSet<Document>> GetQueryableMockDocumentDbSet() 
{ 
    var data = new List<Document> { GetDocument(111, 11), GetDocument(222, 22), GetDocument(333, 33) }.AsQueryable(); 
    var mockDocumentDbSet = new Mock<DbSet<Document>>(); 
    mockDocumentDbSet.As<IQueryable<Document>>().Setup(m => m.Provider).Returns(data.Provider); 
    mockDocumentDbSet.As<IQueryable<Document>>().Setup(m => m.Expression).Returns(data.Expression); 
    mockDocumentDbSet.As<IQueryable<Document>>().Setup(m => m.ElementType).Returns(data.ElementType); 
    mockDocumentDbSet.As<IQueryable<Document>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); 
    return mockDocumentDbSet; 
} 

private static Document GetDocument(int documentId, int userId) 
{ 
    return new Document 
    { 
     DocumentId = documentId, 
     UserId = userId, 
     DateCreated = DateTime.Now.AddDays(-1), 
     DocumentGuid = Guid.NewGuid(), 
    }; 
} 

回答

25

你可以設置你的模擬DbSet的Add()方法的回調將在您的支持列表添加菜單項:

private static Mock<DbSet<Document>> GetQueryableMockDocumentDbSet() 
{ 
    var data = new List<Document> { GetDocument(111, 11), GetDocument(222, 22), GetDocument(333, 33) }; 

    var mockDocumentDbSet = new Mock<DbSet<Document>>(); 
    mockDocumentDbSet.As<IQueryable<Document>>().Setup(m => m.Provider).Returns(data.AsQueryable().Provider); 
    mockDocumentDbSet.As<IQueryable<Document>>().Setup(m => m.Expression).Returns(data.AsQueryable().Expression); 
    mockDocumentDbSet.As<IQueryable<Document>>().Setup(m => m.ElementType).Returns(data.AsQueryable().ElementType); 
    mockDocumentDbSet.As<IQueryable<Document>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); 
    mockDocumentDbSet.Setup(m => m.Add(It.IsAny<Document>())).Callback<Document>(data.Add); 
    return mockDocumentDbSet; 

}

你的後續調用First()應該能夠檢索該項目。

+1

這現在工作正如我所希望的,謝謝你加載。 – jonaglon 2015-02-10 16:18:03

+0

乾杯。這從字面上挽救了我的生命。 – bgs264 2016-02-23 14:14:55

+0

這不適用於像「FirstOrDefaultAsync」這樣的異步調用。 源IQueryable的提供者不會實現IDbAsyncQueryProvider。 修復此鏈接: https://msdn.microsoft.com/en-us/data/dn314429#async – Max 2016-04-05 12:55:31

相關問題