如何对包含数据库事务的代码进行单元测试

3
如何在下面的代码周围放置单位:
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() 存在问题。错误提示为无法像使用它一样。

请给出建议。


请发布您所遇到的确切错误。 - Mike Stockdale
3个回答

0

我也遇到了同样的问题,解决起来相当棘手。

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

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

我已经在这个答案中详细介绍了这个过程。


-1
一个问题?为什么你要在单元测试中尝试启动一个事务?
如果你使用Moq框架模拟你的存储库并从存储库返回所需的内容,那么这将很容易。
实际上,我认为在单元测试中启动BeginTransaction()不是一个好的做法。
希望这可以帮助到你。

我正在测试存储库层的代码,因此无法模拟存储库层。您能否解释一下为什么在单元测试中使用事务不是一个好的实践? - Tun
我的意思是不要使用BeginTransaction。使用这个 using (var ts = new TransactionScope()),使用TransactionScope,如果你不使用Complete方法,事务将无法完成。如果你使用BeginTransaction,你需要调用Rollback来取消事务。 - Oscar Bralo

-1

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

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接