繁体   English   中英

EF Moq单元测试,不确定验证

[英]EF Moq Unit Test, unsure verify

我对单元测试完全不熟悉。 我从不同的人那里读了许多“教程”,我决定使用msdn解决方案。

我使用这个https://msdn.microsoft.com/en-us/library/dn314429(v=vs.113).aspx作为我的测试,我感兴趣的是“ 测试非查询场景 ”。

根据这篇文章,我试着测试我简单的CRUD的Create()动作。

这是我的代码( FinancialAssistantEntities是我的DbContext (EF数据库优先)):

语境:

public partial class FinancialAssistantEntities : DbContext
{
    public FinancialAssistantEntities()
        : base("name=FinancialAssistantEntities")
    {
    }
    .
    .
    .
    public virtual DbSet<FAWallet> FAWallet { get; set; }
}

存储库方法:(我注释掉了我的事务的使用 ,因为从测试方法运行它会导致错误“在应用程序配置文件中找不到名为'FinancialAssistantEntities'的连接字符串。”),

public async Task<bool> CreateWallet(FAWallet model)
{
    using (var context = Context)
    {
        // transaction with IsolationLevel
        //using (var tran = context.Database.BeginTransaction(IsolationLevel.ReadUncommitted))
        {
            try
            {                       
                context.FAWallet.Add(model);
                //context.SaveChanges();
                await context.SaveChangesAsync();
                //tran.Commit();
                return true;
            }
            catch (Exception ex)
            {
                //tran.Rollback();
                throw ex;
            }
        }
    }
}

测试方法:

[TestMethod]
public void CreateWalletTest()
{
    var wallet = new FAWallet()
    {
        WalletId = Guid.NewGuid(),
        //WalletName = StringHelper.GenerateRandomString(12),
        // admin ID
        WalletUserId = "e6888245-1d9b-431c-a068-aa62932e47ec",
        WalletCreateDate = DateTime.Now,
        WalletEnabled = true
    };

    var mockSet = new Mock<DbSet<FAWallet>>();

    var mockContext = new Mock<FinancialAssistantEntities>();
    mockContext.Setup(x => x.FAWallet).Returns(mockSet.Object);

    var walletRepository = new FAWalletRepository(mockContext.Object);
    walletRepository.CreateWallet(wallet).Wait();

    mockSet.Verify(x => x.Add(It.IsAny<FAWallet>()), Times.Once());
    mockContext.Verify(x => x.SaveChangesAsync(), Times.Once()); 
}

首先,我不知道评论交易的使用是否是个好主意,尽管我对测试还不太了解。

其次,我的测试总是过去。 我甚至注释掉了WalletName属性的集合,因为这个字段不可为空,所以看起来我做错了。

前言

在我们开始检查您的问题的各个部分之前,让我明确一下,主要问题不在于单元测试。 相反,它是关于面向对象编程和一些分析。

分析问题空间

让我们看看你在评论中写的内容:

我在其他线程下读过像你这样的类似答案,但我的意思是测试我的错误。 我有一些用户仅部分填充的对象,之后系统自动填充其他字段,例如。 创建日期,创建用户等。当我想念填充其中一些字段时, SaveChanges()会给我一个错误。

您正在从错误的角度接近此任务。

我为什么这么说? 因为:

  1. 您正在使用Entity Framework ORM( EF持久性模型作为行为的来源,该模型负责给定的业务交互

  2. 您希望EF进行此类验证

  3. 您想通过EF机制测试所有这些。 你正在测试错误的东西

解决问题

你真正想要做的就是将你的模型融入EF的核心。 哪个不好因为:

  • 您将代码紧密地耦合到EF,具有不必要的依赖性
  • 它使您的业务逻辑测试变得困难和缓慢
  • 业务逻辑是代码中最重要和最有价值的部分之一,您(在理想条件下)最终会获得报酬

现在让我们重点关注上面的前三点。

第一:我强烈建议你创建一个可能更少依赖的对象。 为了示例,我们将其称为实体 ,它将包含封装的所有必需行为 就像你提到的那样; 有公共方法来设置属性和其他不变量。

第二:您还可以拥有保护此类型及其所有不变量所需的所有验证。 这种验证的常见位置可以是构造函数或接受和验证它接收的参数的任何公共方法。 如果出现错误,您可以在测试中抛出自定义业务异常并对其进行断言。

这些全部组合成一个对象,被称为; 凝聚力

第三:既然你有一个更清洁的对象,它模拟给定的业务交互,你现在只需要完全隔离地测试这个代码。 这是一件好事,因为它很快,它集中并且不会加载大量的依赖项(与使用EF的集成测试相比)。


一切都很顺利

当然,就像所有东西一样,这一切都需要付出代价。 那就是当你将某些东西与系统分开时,你可能会引入另一层间接。 这就是您现在需要将“域模型”映射到EF持久性模型,反之亦然。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM