【问题标题】:How to unit test code that includes a database transaction如何对包含数据库事务的代码进行单元测试
【发布时间】:2014-04-19 17:50:36
【问题描述】:

如何在以下代码周围放置单位:

public DbContextTransaction QTTransactionBegin()
    {
        return Database.BeginTransaction();
    }

public int CreateCampaign(CreateCampaignModel createCampaignModel)
    {
        using (var transaction = _qtContext.QTTransactionBegin())
        {
            try
            {
                var campaign = new Campaign();
                campaign.CampaignCode = createCampaignModel.CampaignCode;
                campaign.CampaignDescription = createCampaignModel.CampaignDescription;
                campaign.CampaignDate = createCampaignModel.CampaignDate;
                campaign.CampaignNotes = createCampaignModel.CampaignNotes;
                campaign.OwnerUserID = createCampaignModel.OwnerUserID;
                campaign.AddedOn = DateTime.Now;
                campaign.AddedBy = createCampaignModel.OwnerUserName;
                campaign.UpdatedOn = DateTime.Now;
                campaign.UpdatedBy = createCampaignModel.OwnerUserName;
                campaign.CampaignSegments = GetCampaignSegmentList(createCampaignModel);

                var campaignId = AddOrUpdateCampaign(campaign);
                transaction.Commit();
                return campaignId;
            }
            catch (Exception ex)
            {
                transaction.Rollback();
            }
        }
        return 0;
    }

谁能告诉我如何对上面的代码进行单元测试?

我尝试了如下代码:

Database_database;

    [TestInitialize]
    public void SetUp()
    {
        _qtDALMock = _factory.CreateMock<IQTDAL>();
        _campaignRepository = new CampaignRepository(_qtDALMock.MockObject);
    }
 [TestMethod]
    public void Check_CreateCampaign_Test()
    {
        // arrange 
        const int expectedCampaignId = 1;
        var createCampaign = QueryToolDummies.CreateCampaignModel;

        _database.BeginTransaction();
        _qtDALMock.Expects.One.MethodWith(x => x.QTTransactionBegin())
            .WillReturn(_database.BeginTransaction());
        _qtDALMock.Expects.One.Method(x => x.AddOrUpdateCampaign(null))
            .With(Is.TypeOf<Campaign>())
            .WillReturn(expectedCampaignId);

        // act
        var result = _campaignRepository.CreateCampaign(createCampaign);

        // assert
        Assert.IsNotNull(result);
    }

这个_database.BeginTransaction() 有问题。错误说不能像它一样使用。

请指教。

【问题讨论】:

  • 请发布您遇到的确切错误

标签: c# unit-testing asp.net-mvc-4 tdd moq


【解决方案1】:

我遇到了同样的问题,解决起来非常棘手。

我尝试为公开BeginTransaction() 方法的上下文创建一个包装类,但最终您需要模拟BeginTransaction() 返回的DbContextTransaction 在测试时,但DbContextTransaction 既没有接口或公共构造函数。

最后,我编写了一个事务管理器类,它创建和管理自己的事务并公开用于开始、提交和回滚事务的方法。然后可以伪造该管理器类以及返回它的服务,从而允许对使用事务的代码进行全面测试。

我已经完整地写了in this answer

【讨论】:

    【解决方案2】:

    一个问题?您为什么要尝试将事务启动到单元测试中?

    如果您使用Moq framework 模拟您的存储库并返回您需要从存储库返回的内容,将会很容易。

    事实上,我认为在单元测试中启动BeginTransaction() 并不是一个好习惯。

    希望对你有帮助

    【讨论】:

    • 我正在从存储库层测试代码。所以我无法模拟存储库层。你能解释一下为什么单元测试中的事务不是一个好习惯吗?
    • 我的意思是不要使用 BeginTransaction。使用这个 using (var ts = new TransactionScope()),使用 TransactionScope,如果你不使用 Complete 方法,事务将不会完成。如果您使用 BeginTransaction,则需要调用 Rollback 以不执行事务。
    【解决方案3】:

    您正在尝试对多个单元进行单元测试。

    假设上面的代码是您的“数据层”/存储库,那么您正在执行集成测试,因为测试涉及多个单元。

    您可以在测试类中包含数据库的设置/拆卸,并使用有效和无效数据调用 SUT(被测对象)以验证预期行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-02
      • 2015-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多