2011-09-02 28 views
2

我使用實體框架4.1的數據庫訪問,並希望單元測試下面的代碼:您如何使用痣來查詢EntityFramework 4.1中的數據庫痣DbContext?

// Get all the entities including children 
using (MyContext context = new MyContext()) 
{ 
    return context.EmployeeProfiles.Include("EmployeeProperties").ToList(); 
} 

我使用的痣但是我堅持去痣了數據庫的依賴。實體框架中的哪一點我應該開始冒出來。

我正在關注這個example,但它適用於LINQ-to-SQL。

我也在考慮調試/跟蹤實體框架以確定在調用數據庫之前攔截出哪個函數。 但是,似乎沒有可用於Entity Framework 4.1追蹤的源代碼。見discussion

任何人都可以指導我哪些功能我應該在DbContext中剔除,這樣我就可以獲得EmployeeProfiles的列表了嗎?

+0

有趣的問題,因爲我想知道是否有必要單元測試這種類型的代碼。我假設這是一個存儲庫的一部分,基本上是像'GetFullEmployeeProfiles'這樣的方法的實現,並且您希望編寫一個單元測試以確認您實際上是否使用'EmployeeProperties'填充了'EmployeeProfiles'。 – Rudi

+0

是的代碼是存儲庫的一部分,我們正在對該區域進行單元測試。但是,我希望進一步進行單元測試,並鼓勵實體框架,並返回我的預期實體。 我發現嘲笑DBContext最接近的信息不使用痣: http://romiller.com/2010/09/07/ef-ctp4-tips-tricks-testing-with-fake-dbcontext/ – walleye

回答

0

它看起來很像我,而不是通過Repository模式去除對EF的依賴,你試圖模擬EF的特定行爲。我不明白要做到這一點,這將是非常困難的,EF並不意味着被嘲笑。

你的倉庫大概是這樣的:

public interface IRepository 
{ 
     IEnumerable<EmployeeProfiles> EmployeeProfiles { get; } 
} 

public class Repository 
{ 
    public IEnumerable<EmployeeProfiles> EmployeeProfiles 
    { 
     get 
     { 
      // Get all the entities including children  
      using (MyContext context = new MyContext())  
      { 
       return context.EmployeeProfiles.Include("EmployeeProperties").ToList();  
      } 
     } 
    } 
} 

這種方式,你已經取消了對EmployeeProfiles如何返回倉庫的依賴。現在,您可以模擬走你的心臟的內容(尚未使用摩爾),但起訂量,你會做這樣的事情:

public void TestEmptyList() 
{ 
    var mock = new Mock<IRepository>(); 
    var expected = new List<EmployeeProfiles>(); 
    mock.SetupGet(ep => ep.EmployeeProfiles).Returns(expected); 

    var actual = mock.Object.EmployeeProfiles; 

    Assert.AreEqual(expected, actual); 
} 

所以,如果你把方法/屬性要抽象掉從數據庫到存儲庫接口,然後你可以模擬出你想測試的任何值,它可能會返回。

也許你正在這樣做,我不確定。我不明白你爲什麼想單元測試EF,你希望獲得什麼?這將是非常困難的,它不是被設計成被嘲笑(很少接口/虛擬)。任何嘲笑你返回的數據,這是你真正感興趣的所有事情都將按照上述方式完成。

+0

唯一的嘲笑EF的原因是爲了增加版本庫和EF之間的代碼覆蓋率。我認爲使用痣和掛鉤EF將是一個簡單的操作。 目前,我們使用單元測試來單元測試我們的存儲庫層。 感謝您的幫助。 – walleye

+0

嘲諷EF *很難,但這是獲得真正單元測試的唯一方法。用存儲庫嘲弄看起來很容易,但它實際上爲模擬操作提供了一個綠燈,該操作使用Linq作爲對象而不是Linq to Entities。所以我們並不真正測試我們的應用程序正在使用的東西。我目前正在修改T4模板,使DbContext實現一個接口,以便我可以嘲笑它。仍然不確定如何處理更改跟蹤等高級操作。恐怕我們可能不得不退回到實際運行數據庫的集成測試。 –

+0

是的,我認爲大多數人會認爲這就是集成測試的目的。無可否認,L2O和L2E之間存在(相當大的)差異,但在單元測試中,這應該不是真正的問題,但同時應該意識到這種差異。也許問題是對象關係映射本身的概念。 – nicodemus13

0

這是完全可能的,在我看來,這是完全有效的。是的,您可以使用存儲庫模式並模擬您的存儲庫,而且這通常足夠好。

但是,有兩個參數,我們已經看到了嘲諷EF:

  1. EF已經在實際的數據庫抽象/存儲庫,寫另一個倉庫周圍是沒有必要的。
  2. 您通過EF編寫的任何存儲庫是您的代碼。因此,您應該對其進行測試,遲早您會最終添加需要覆蓋的邏輯。

這是一個神聖的戰爭在這一點上,但有支持你在做什麼的論點。

所以,要用痣做到這一點,你需要做兩件事。首先,更改創建DbContext的模板,以便所有表的返回類型爲IDbSet<>而不是DbSet<>

然後,在您的測試項目中,爲IDbSet添加一個測試類實現。我發現this one工作良好。現在

,在您的測試,你可以做到以下幾點:

List<EmployeeProfile> testProfiles = /*your test data here*/; 
MMyContext.AllInstances.EmployeeProfilesGet = (instance) => 
{ 
    return new InMemoryDbSet<EmployeeProfile>(testProfiles); 
}; 


// Get all the entities including children 
using (MyContext context = new MyContext()) 
{ 
    return context.EmployeeProfiles.Include("EmployeeProperties").ToList(); 
} 

它的快速,簡單,並允許您對代碼進行測試,一直到非常指向離開你的控制。