Dot-Net

Entity Framework 4.1 的假 DbContext 進行測試

  • August 1, 2011

我正在使用本教程來偽造我的 DbContext 並進行測試:http ://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic -儲存庫/

但我必須更改 FakeMainModuleContext 實現以在我的控制器中使用:

public class FakeQuestiona2011Context : IQuestiona2011Context
{
   private IDbSet<Credencial> _credencial;
   private IDbSet<Perfil> _perfil;
   private IDbSet<Apurador> _apurador;
   private IDbSet<Entrevistado> _entrevistado;
   private IDbSet<Setor> _setor;
   private IDbSet<Secretaria> _secretaria;
   private IDbSet<Pesquisa> _pesquisa;
   private IDbSet<Pergunta> _pergunta;
   private IDbSet<Resposta> _resposta;

   public IDbSet<Credencial> Credencial { get { return _credencial ?? (_credencial = new FakeDbSet<Credencial>()); } set { } }
   public IDbSet<Perfil> Perfil { get { return _perfil ?? (_perfil = new FakeDbSet<Perfil>()); } set { } }
   public IDbSet<Apurador> Apurador { get { return _apurador ?? (_apurador = new FakeDbSet<Apurador>()); } set { } }
   public IDbSet<Entrevistado> Entrevistado { get { return _entrevistado ?? (_entrevistado = new FakeDbSet<Entrevistado>()); } set { } }
   public IDbSet<Setor> Setor { get { return _setor ?? (_setor = new FakeDbSet<Setor>()); } set { } }
   public IDbSet<Secretaria> Secretaria { get { return _secretaria ?? (_secretaria = new FakeDbSet<Secretaria>()); } set { } }
   public IDbSet<Pesquisa> Pesquisa { get { return _pesquisa ?? (_pesquisa = new FakeDbSet<Pesquisa>()); } set { } }
   public IDbSet<Pergunta> Pergunta { get { return _pergunta ?? (_pergunta = new FakeDbSet<Pergunta>()); } set { } }
   public IDbSet<Resposta> Resposta { get { return _resposta ?? (_resposta = new FakeDbSet<Resposta>()); } set { } }

   public void SaveChanges()
   {
       // do nothing (probably set a variable as saved for testing)
   }
}

我的測試是這樣的:

[TestMethod]
public void IndexTest()
{
   IQuestiona2011Context fakeContext = new FakeQuestiona2011Context();
   var mockAuthenticationService = new Mock<IAuthenticationService>();

   var apuradores = new List<Apurador>
   {
       new Apurador() { Matricula = "1234", Nome = "Acaz Souza Pereira", Email = "acaz@telecom.inf.br", Ramal = "1234" },
       new Apurador() { Matricula = "4321", Nome = "Samla Souza Pereira", Email = "samla@telecom.inf.br", Ramal = "4321" },
       new Apurador() { Matricula = "4213", Nome = "Valderli Souza Pereira", Email = "valderli@telecom.inf.br", Ramal = "4213" }
   };
   apuradores.ForEach(apurador => fakeContext.Apurador.Add(apurador));

   ApuradorController apuradorController = new ApuradorController(fakeContext, mockAuthenticationService.Object);
   ActionResult actionResult = apuradorController.Index();

   Assert.IsNotNull(actionResult);
   Assert.IsInstanceOfType(actionResult, typeof(ViewResult));

   ViewResult viewResult = (ViewResult)actionResult;

   Assert.IsInstanceOfType(viewResult.ViewData.Model, typeof(IndexViewModel));

   IndexViewModel indexViewModel = (IndexViewModel)viewResult.ViewData.Model;

   Assert.AreEqual(3, indexViewModel.Apuradores.Count);
}

我做得對嗎?

不幸的是,您沒有做對,因為那篇文章是錯誤的。它假裝這FakeContext將使您的程式碼可單元測試,但它不會。一旦你暴露IDbSetIQueryable你的控制器並且你用記憶體集合偽造集合,你永遠不能確定你的單元測試真的測試你的程式碼。在您的控制器中編寫一個 LINQ 查詢非常容易,它將通過您的單元測試(因為FakeContext使用 LINQ-to-Objects)但在執行時失敗(因為您的真實上下文使用 LINQ-to-Entities)。這使您的單元測試的全部目的毫無用處。

我的意見:如果您想將集合公開給控制器,請不要擔心偽造上下文。而是使用帶有真實數據庫的集成測試進行測試。這是驗證控制器中定義的 LINQ 查詢是否符合您的預期的唯一方法。

當然,如果你想只呼叫ToListFirstOrDefault在你的集合上呼叫,你FakeContext會很好地為你服務,但是一旦你做了更複雜的事情,你很快就會找到一個陷阱(只需將字元串*“無法翻譯成商店表達式”*放入Google - 所有這些問題只會在您執行 Linq-to-entities 時出現,但它們會通過 Linq-to-objects 的測試)。

這是一個很常見的問題,因此您可以查看其他一些範例:

引用自:https://stackoverflow.com/questions/6904139