NUnit - 用于测试事务的单元测试案例

5

我有一个如下的方法。

我想为以下方法编写两个测试用例。

1)提交数据成功的事务

2)回滚数据失败的事务

如何编写涉及事务的测试用例并使其成功和失败?

public async Task<List<string>> UpdateRequest(MetaData data, List<string> Ids, string requestedBy)
{
    var transaction = await _databaseUtility.CreateTransaction(ConnectionString);

    var messages = new List<string>();

    try
    {
        // Update data
        await _testDal.Update(data, requestedBy, transaction);

        // Update status
        await _sampleDal.UpdateStatus(Ids, requestedBy, transaction);

        // Update saved data
        await _testDal.UpdateSavedData(data, requestedBy, transaction);

        _databaseUtility.CommitTransaction(transaction);
    }
    catch (Exception exception)
    {
        _databaseUtility.RollbackTransaction(transaction);
    }

    return messages;
}

你在哪里向 messages 列表添加值? - Pavel Anikhouski
2个回答

4

您可以通过使用 NUnit 内置的 TestCaseSource 属性和 TestCaseData 类来实现它。

[TestCaseSource(nameof(TestCases))]
public List<string> TestTransaction(MetaData data, List<string> ids, string requestedBy)
{
    return testObject.UpdateRequest(data, ids, requestedBy).GetAwaiter().GetResult();
}

public static IEnumerable TestCases
{
    get
    {
        //successful
        yield return new TestCaseData(new MetaData(), new List<string> { "1", "2" }, "test").Returns(new List<string> { "test1", "test2" });
        //failed
        yield return new TestCaseData(null, new List<string> { "1", "2" }, "test").Returns(new List<string> { "test1", "test2" });
        //another failed
        yield return new TestCaseData(new MetaData(), new List<string> { "1", "2" }, string.Empty).Returns(new List<string> { "test1", "test2" });
    }
}

这里有几个要点:
  • 为什么在UpdateRequest方法中需要一个消息List?它只是被初始化,没有添加值。在上面的代码片段中,从UpdateRequest方法返回的消息列表仅与期望结果匹配,但在这里也可以编写任何Assert
  • 失败的事务取决于您的逻辑,您可以传递导致异常的无效数据,在代码片段中我使用了空的MetadatarequestedBy
  • async Task<List<string>> 返回结果是同步执行的,以匹配预期的返回结果 List<string>。异步测试用例源是在NUnit github上提出的建议

作为一种选择,您还可以编写单独的成功和失败交易测试,并异步调用UpdateRequest方法。

到目前为止,您尚未分享组件的详细信息,很难对DAL进行假设,但如果您想为Update方法使用模拟,则可以尝试Moq库和Task.FromResult方法用于响应/返回值,如此答案中所述。


4

我认为你在这里有两个问题:

  1. 您在单元测试中使用了异步和等待,这意味着您的代码会在实际完成之前继续运行。
    您可以阅读这篇文章https://johnthiriet.com/removing-async-void/#

    我将解释其中的问题, 确保 await _testDal.Update(data, requestedBy, transaction); Update() 函数返回一个 Task
    然后您可以使用 _testDal.Update(data, requestedBy, transaction).Wait() 进行单元测试。
    对于常规代码,需要使用await调用。这将使您的测试代码等待 Update 完成,而常规代码保持不变。

  2. 我建议使用 NSubstitute 等模拟服务https://nsubstitute.github.io/来模拟响应。模拟服务将使用反射替换实现 _testDal 接口或类的内容。
    这样当您调用 Update() 函数时,可以向其传递某些参数,并在将这些参数传递到函数时抛出异常。
    并传递另一组参数,并返回正确的消息。

如果你想传递不同的参数,可以使用Nunit TestCase(new[] params...),并向相同的单元测试传递不同的参数集。 但是对于PassTest和FailTest,我会使用2个或更多不同的测试。

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