.net - 伪造 Entity Framework 4.1 的 DbContext 进行测试

标签 .net asp.net-mvc unit-testing entity-framework tdd

我正在使用本教程来伪造我的 DbContext 并测试:http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/

但我必须更改 FakeMainModuleContext 实现以在我的 Controller 中使用:

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 将使您的代码单元可测试,但事实并非如此。一旦您向 Controller 公开 IDbSet 或 IQueryable 并使用内存集合伪造该集合,您将永远无法确定您的单元测试是否真正测试了您的代码。在 Controller 中编写 LINQ 查询非常容易,该查询将通过单元测试(因为 FakeContext 使用 LINQ-to-Objects),但在运行时失败(因为您的真实上下文使用 LINQ-to-Entities) )。这使得单元测试的整个目的变得毫无意义。

我的观点:如果您想向 Controller 公开集合,请不要费心伪造上下文。相反,使用与真实数据库的集成测试进行测试。这是验证 Controller 中定义的 LINQ 查询是否符合您的预期的唯一方法。

当然,如果您只想在集合上调用 ToListFirstOrDefault,您的 FakeContext 将为您提供良好的服务,但一旦您执行更多操作复杂,你很快就能找到陷阱(只需将字符串“无法翻译成商店表达式”输入Google - 所有这些问题只有在运行Linq-to-entities时才会出现,但它们会通过您使用 Linq-to-objects 进行的测试)。

这是一个很常见的问题,因此您可以查看其他一些示例:

关于.net - 伪造 Entity Framework 4.1 的 DbContext 进行测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6904139/

相关文章:

java - App Engine Cloud Endpoints 单元测试,Data Nucleus 问题,可能吗?

javascript - 使用 mocha 模拟 Nodejs 中的函数

c# - 无法使用 C# 和 SSH.NET 从 Windows 运行 Unix 服务器中的用户脚本

c# - MVC 3,url参数不分开

c# - async await 在调用异步方法时返回 Task<List<T>> 而不是 List<T>

javascript - 脚本 mvc 中复选框的选择器

java - Play Framework 2.0 单元测试

c# - 动态创建代理类

asp.net-mvc - MVC3 Razor 和 Javascript - 大量绿色语法错误

c# - Asp.Net MVC 5 身份创建数据库管理界面