c# 测试异步任务 - 测试用例忽略等待 - NullReferenceException

c# testing async task - test case ignores await - NullReferenceException

我正在使用 NUnit、Shouldly 和 Entity Framework 内存中的 SQLite 数据库进行集成测试,并卡在我的两个不执行任何数据库调用的测试用例上(未执行等待)。

控制器:

[HttpPost("DeleteOrganisations")]
public async Task<IActionResult> DeleteOrganisations([FromBody] DeleteOrganisationsModel model)
{
    //Test case 2 fails here
    if (model == null || !ModelState.IsValid)
    {
        return Ok(new GenericResultModel(_localizer["An_unexpected_error_has_occurred_Please_try_again"]));
    }

    List<OrganisationModel> organisations = (await _organisationService.GetOrganisations(model.OrganisationIds)).ToList();

    //Test case 3 fails here
    if (organisations == null || organisations.Count == 0)
    {
        return Ok(new GenericResultModel(_localizer["Could_not_find_organisations"]));
    }

    StatusModel status = await _statusService.GetStatus(StatusTypeEnum.StatusType.Organisation, StatusEnum.Status.Removed);

    if (status == null)
    {
        return Ok(new GenericResultModel(_localizer["Could_not_find_status"]));
    }

    foreach (OrganisationModel organisation in organisations)
    {
        organisation.StatusId = status.Id;
    }

    List<OrganisationModel> updatedOrganisations = (await _organisationService.UpdateOrganisations(organisations)).ToList();

    if (updatedOrganisations == null || updatedOrganisations.Count == 0)
    {
        return Ok(new GenericResultModel(_localizer["Could_not_remove_organisations"]));
    }

    if (updatedOrganisations.Count == 1)
    {
        return Ok(new GenericResultModel { Id = updatedOrganisations[0].Id });
    }

    return Ok(new GenericResultModel { Count = updatedOrganisations.Count });
}

测试:

[TestFixture]
public class DeleteOrganisations : TestBase
{
    private OrganisationController _organisationController;

    [OneTimeSetUp]
    public void OneTimeSetUp()
    {
        //Controller
        _organisationController = new OrganisationController(null, Mapper, OrganisationService, StatusService, AuthenticationService);

        //Object Mother
        ObjectMother.InsertTestData();
    }

    public static IEnumerable TestCases
    {
        get
        {
            yield return new TestCaseData(new DeleteOrganisationsModel { OrganisationIds = new List<int>() { 1 } }, 0, 1).SetName("DeleteOrganisations_Should_Delete_Data_When_OrganisationId_Exist");

            yield return new TestCaseData(new DeleteOrganisationsModel { OrganisationIds = null }, 0, 0).SetName("DeleteOrganisations_Should_Not_Delete_Data_When_Null");
            yield return new TestCaseData(new DeleteOrganisationsModel { OrganisationIds = new List<int>() { 2 } }, 0, 0).SetName("DeleteOrganisations_Should_Not_Delete_Data_When_OrganisationId_Not_Exist");
        }
    }

    [Test, TestCaseSource(nameof(TestCases))]
    public async Task Test(DeleteOrganisationsModel model, int removedOrganisationCountBefore, int removedOrganisationCountAfter)
    {
        //Before
        int resultBefore = Database.Organisation.Include(o => o.Status).Count(o => o.Status.Name == StatusEnum.Status.Removed.ToString());

        resultBefore.ShouldBe(removedOrganisationCountBefore);

        //Delete
        await _organisationController.DeleteOrganisations(model);

        //After
        int resultAfter = Database.Organisation.Include(o => o.Status).Count(o => o.Status.Name == StatusEnum.Status.Removed.ToString());

        resultAfter.ShouldBe(removedOrganisationCountAfter);
    }
}

测试用例 1 通过,因为

StatusModel status = await _statusService.GetStatus(StatusTypeEnum.StatusType.Organisation, StatusEnum.Status.Removed);

已调用并等待结果。

测试用例 2 和 3 失败,因为函数中从来没有等待(if 语句)。

Message: System.NullReferenceException : Object reference not set to an instance of an object.

我可能可以为不执行任何 await 语句的结果创建另一个测试并跳过新测试函数的异步任务,但随后我会收到消息说:

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

测试可能会通过,但我不喜欢两次测试加上语法错误的想法。

你会怎么做?

编辑

异常:

Message: System.NullReferenceException : Object reference not set to an instance of an object.

堆栈跟踪:

Test Name:  DeleteOrganisations_Should_Not_Delete_Data_When_OrganisationId_Not_Exist
Test FullName:  MyProject.Test.Api.Administration.Organisation.DeleteOrganisations.DeleteOrganisations_Should_Not_Delete_Data_When_OrganisationId_Not_Exist
Test Source:    C:\Users\User\Documents\Visual Studio 2017\Projects\MyProject\MyProject.Test\Api\Administration\Organisation\DeleteOrganisations.cs : line 42
Test Outcome:   Failed
Test Duration:  0:00:02.48

Result StackTrace:  at MyProject.Api.Controllers.Administration.OrganisationController.<DeleteOrganisations>d__8.MoveNext() in C:\Users\User\Documents\Visual Studio 2017\Projects\MyProject\MyProject.Api\Controllers\Administration\OrganisationController.cs:line 114
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at MyProject.Test.Api.Administration.Organisation.DeleteOrganisations.<Test>d__4.MoveNext() in C:\Users\User\Documents\Visual Studio 2017\Projects\MyProject\MyProjectTest\Api\Administration\Organisation\DeleteOrganisations.cs:line 49
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(Object invocationResult)
   at NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext context)
Result Message: System.NullReferenceException : Object reference not set to an instance of an object.

Facepalm - 我忘记在测试库中注入定位器 class。对不起各位我的错。

这一行就在这里:

if (organisations == null || organisations.Count == 0)
{
    return Ok(new GenericResultModel(_localizer["Could_not_find_organisations"]));
}